private void Fill <TObject>( IFiller <TObject> filler, PdfDictionary node ) { PdfArray kidsObject = (PdfArray)node.Resolve(PdfName.Kids); if (kidsObject == null) // Leaf node. { PdfArray namesObject = (PdfArray)node.Resolve(pairsKey); for ( int index = 0, length = namesObject.Count; index < length; index += 2 ) { filler.Add(namesObject, index); } } else // Intermediate node. { foreach (PdfDirectObject kidObject in kidsObject) { Fill(filler, (PdfDictionary)kidObject.Resolve()); } } }
/** * <summary>Splits a full node.</summary> * <remarks>A new node is inserted at the full node's position, receiving the lower half of its * children.</remarks> * <param name="nodes">Parent nodes.</param> * <param name="fullNodeIndex">Full node's position among the parent nodes.</param> * <param name="childrenTypeName">Full node's children type.</param> */ private void SplitFullNode( PdfArray nodes, int fullNodeIndex, PdfName childrenTypeName ) { // Get the full node! PdfDictionary fullNode = (PdfDictionary)nodes.Resolve(fullNodeIndex); PdfArray fullNodeChildren = (PdfArray)fullNode.Resolve(childrenTypeName); // Create a new (sibling) node! PdfDictionary newNode = new PdfDictionary(); PdfArray newNodeChildren = new PdfArray(); newNode[childrenTypeName] = newNodeChildren; // Insert the new node just before the full! nodes.Insert(fullNodeIndex, File.Register(newNode)); // NOTE: Nodes MUST be indirect objects. // Transferring exceeding children to the new node... for (int index = 0, length = Children.InfoImpl.Get(childrenTypeName).MinCount; index < length; index++) { PdfDirectObject removedChild = fullNodeChildren[0]; fullNodeChildren.RemoveAt(0); newNodeChildren.Add(removedChild); } // Update the key limits! UpdateNodeLimits(newNode, newNodeChildren, childrenTypeName); UpdateNodeLimits(fullNode, fullNodeChildren, childrenTypeName); }
/** * <summary>Gets the given node's entries count.</summary> * <param name="node">Current node.</param> */ private int GetCount( PdfDictionary node ) { PdfArray children = (PdfArray)node.Resolve(pairsKey); if (children != null) // Leaf node. { return(children.Count / 2); } else // Intermediate node. { children = (PdfArray)node.Resolve(PdfName.Kids); int count = 0; foreach (PdfDirectObject child in children) { count += GetCount((PdfDictionary)child.Resolve()); } return(count); } }
/** * <summary>Gets the stream body.</summary> * <param name="decode">Defines whether the body has to be decoded.</param> */ public IBuffer GetBody( bool decode ) { if (decode) { // Get 'Filter' entry! /* * NOTE: It defines possible encodings applied to the stream. */ PdfDirectObject filterObj = header[PdfName.Filter]; if (filterObj != null) // Stream encoded. { /* * NOTE: If the stream is encoded, we must decode it before continuing. */ PdfDataObject filterDataObj = files.File.Resolve(filterObj); PdfDataObject decodeParms = header.Resolve(PdfName.DecodeParms); if (filterDataObj is PdfName) // PdfName. { PdfDictionary filterDecodeParms = (PdfDictionary)decodeParms; body.Decode(Filter.Get((PdfName)filterDataObj), filterDecodeParms); } else // MUST be PdfArray. { IEnumerator <PdfDirectObject> filterObjIterator = ((PdfArray)filterDataObj).GetEnumerator(); IEnumerator <PdfDirectObject> decodeParmsIterator = (decodeParms != null ? ((PdfArray)decodeParms).GetEnumerator() : null); while (filterObjIterator.MoveNext()) { PdfDictionary filterDecodeParms; if (decodeParmsIterator == null) { filterDecodeParms = null; } else { decodeParmsIterator.MoveNext(); filterDecodeParms = (PdfDictionary)files.File.Resolve(decodeParmsIterator.Current); } body.Decode(Filter.Get((PdfName)files.File.Resolve(filterObjIterator.Current)), filterDecodeParms); } } // Update 'Filter' entry! header[PdfName.Filter] = null; // The stream is free from encodings. } } return(body); }
/** * <summary>Gets the given node's children.</summary> * <param name="node">Parent node.</param> * <param name="pairs">Pairs key.</param> */ public static Children Get( PdfDictionary node, PdfName pairsKey ) { PdfName childrenTypeName; if (node.ContainsKey(PdfName.Kids)) { childrenTypeName = PdfName.Kids; } else if (node.ContainsKey(pairsKey)) { childrenTypeName = pairsKey; } else { throw new Exception("Malformed tree node."); } PdfArray children = (PdfArray)node.Resolve(childrenTypeName); return(new Children(node, children, childrenTypeName)); }
/** * <summary>Adds an entry under the given tree node.</summary> * <param name="key">New entry's key.</param> * <param name="value">New entry's value.</param> * <param name="overwrite">Whether the entry is allowed to replace an existing one having the same * key.</param> * <param name="nodeReference">Current node reference.</param> */ private void Add( TKey key, TValue value, bool overwrite, PdfDictionary node ) { Children children = Children.Get(node, pairsKey); if (children.IsLeaf()) // Leaf node. { int childrenSize = children.Items.Count; int low = 0, high = childrenSize - children.Info.ItemCount; while (true) { if (low > high) { // Insert the entry! children.Items.Insert(low, key); children.Items.Insert(++low, value.BaseObject); break; } int mid = (mid = ((low + high) / 2)) - (mid % 2); if (mid >= childrenSize) { // Append the entry! children.Items.Add(key); children.Items.Add(value.BaseObject); break; } int comparison = key.CompareTo(children.Items[mid]); if (comparison < 0) // Before. { high = mid - 2; } else if (comparison > 0) // After. { low = mid + 2; } else // Matching entry. { if (!overwrite) { throw new ArgumentException("Key '" + key + "' already exists.", "key"); } // Overwrite the entry! children.Items[mid] = key; children.Items[++mid] = value.BaseObject; break; } } // Update the key limits! UpdateNodeLimits(children); } else // Intermediate node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { bool matched = false; int mid = (low + high) / 2; PdfReference kidReference = (PdfReference)children.Items[mid]; PdfDictionary kid = (PdfDictionary)kidReference.DataObject; PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) // Before the lower limit. { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) // After the upper limit. { low = mid + 1; } else // Limit range matched. { matched = true; } if (matched || // Limit range matched. low > high) // No limit range match. { Children kidChildren = Children.Get(kid, pairsKey); if (kidChildren.IsFull()) { // Split the node! SplitFullNode( children.Items, mid, kidChildren.TypeName ); // Is the key before the split node? if (key.CompareTo(((PdfArray)kid.Resolve(PdfName.Limits))[0]) < 0) { kidReference = (PdfReference)children.Items[mid]; kid = (PdfDictionary)kidReference.DataObject; } } Add(key, value, overwrite, kid); // Update the key limits! UpdateNodeLimits(children); break; } } } }
public virtual TValue this[ TKey key ] { get { PdfDictionary parent = BaseDataObject; while (true) { Children children = Children.Get(parent, pairsKey); if (children.IsLeaf()) // Leaf node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { if (low > high) { return(null); } int mid = (mid = ((low + high) / 2)) - (mid % 2); int comparison = key.CompareTo(children.Items[mid]); if (comparison < 0) { high = mid - 2; } else if (comparison > 0) { low = mid + 2; } else { // We got it! return(WrapValue(children.Items[mid + 1])); } } } else // Intermediate node. { int low = 0, high = children.Items.Count - children.Info.ItemCount; while (true) { if (low > high) { return(null); } int mid = (low + high) / 2; PdfDictionary kid = (PdfDictionary)children.Items.Resolve(mid); PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) { low = mid + 1; } else { // Go down one level! parent = kid; break; } } } } } set { Add(key, value, true); } }
public virtual bool Remove( TKey key ) { PdfDictionary node = BaseDataObject; Stack <PdfReference> nodeReferenceStack = new Stack <PdfReference>(); while (true) { Children nodeChildren = Children.Get(node, pairsKey); if (nodeChildren.IsLeaf()) // Leaf node. { int low = 0, high = nodeChildren.Items.Count - nodeChildren.Info.ItemCount; while (true) { if (low > high) // No match. { return(false); } int mid = (mid = ((low + high) / 2)) - (mid % 2); int comparison = key.CompareTo(nodeChildren.Items[mid]); if (comparison < 0) // Key before. { high = mid - 2; } else if (comparison > 0) // Key after. { low = mid + 2; } else // Key matched. { // We got it! nodeChildren.Items.RemoveAt(mid + 1); // Removes value. nodeChildren.Items.RemoveAt(mid); // Removes key. if (mid == 0 || mid == nodeChildren.Items.Count) // Limits changed. { // Update key limits! UpdateNodeLimits(nodeChildren); // Updating key limits on ascendants... PdfReference rootReference = (PdfReference)BaseObject; PdfReference nodeReference; while (nodeReferenceStack.Count > 0 && !(nodeReference = nodeReferenceStack.Pop()).Equals(rootReference)) { PdfArray parentChildren = (PdfArray)nodeReference.Parent; int nodeIndex = parentChildren.IndexOf(nodeReference); if (nodeIndex == 0 || nodeIndex == parentChildren.Count - 1) { PdfDictionary parent = (PdfDictionary)parentChildren.Parent; UpdateNodeLimits(parent, parentChildren, PdfName.Kids); } else { break; } } } return(true); } } } else // Intermediate node. { int low = 0, high = nodeChildren.Items.Count - nodeChildren.Info.ItemCount; while (true) { if (low > high) // Outside the limit range. { return(false); } int mid = (low + high) / 2; PdfReference kidReference = (PdfReference)nodeChildren.Items[mid]; PdfDictionary kid = (PdfDictionary)kidReference.DataObject; PdfArray limits = (PdfArray)kid.Resolve(PdfName.Limits); if (key.CompareTo(limits[0]) < 0) // Before the lower limit. { high = mid - 1; } else if (key.CompareTo(limits[1]) > 0) // After the upper limit. { low = mid + 1; } else // Limit range matched. { Children kidChildren = Children.Get(kid, pairsKey); if (kidChildren.IsUndersized()) { /* * NOTE: Rebalancing is required as minimum node size invariant is violated. */ PdfDictionary leftSibling = null; Children leftSiblingChildren = null; if (mid > 0) { leftSibling = (PdfDictionary)nodeChildren.Items.Resolve(mid - 1); leftSiblingChildren = Children.Get(leftSibling, pairsKey); } PdfDictionary rightSibling = null; Children rightSiblingChildren = null; if (mid < nodeChildren.Items.Count - 1) { rightSibling = (PdfDictionary)nodeChildren.Items.Resolve(mid + 1); rightSiblingChildren = Children.Get(rightSibling, pairsKey); } if (leftSiblingChildren != null && !leftSiblingChildren.IsUndersized()) { // Move the last child subtree of the left sibling to be the first child subtree of the kid! for (int index = 0, endIndex = leftSiblingChildren.Info.ItemCount; index < endIndex; index++) { int itemIndex = leftSiblingChildren.Items.Count - 1; PdfDirectObject item = leftSiblingChildren.Items[itemIndex]; leftSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Insert(0, item); } // Update left sibling's key limits! UpdateNodeLimits(leftSiblingChildren); } else if (rightSiblingChildren != null && !rightSiblingChildren.IsUndersized()) { // Move the first child subtree of the right sibling to be the last child subtree of the kid! for (int index = 0, endIndex = rightSiblingChildren.Info.ItemCount; index < endIndex; index++) { int itemIndex = 0; PdfDirectObject item = rightSiblingChildren.Items[itemIndex]; rightSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Add(item); } // Update right sibling's key limits! UpdateNodeLimits(rightSiblingChildren); } else { if (leftSibling != null) { // Merging with the left sibling... for (int index = leftSiblingChildren.Items.Count; index-- > 0;) { PdfDirectObject item = leftSiblingChildren.Items[index]; leftSiblingChildren.Items.RemoveAt(index); kidChildren.Items.Insert(0, item); } nodeChildren.Items.RemoveAt(mid - 1); leftSibling.Delete(); } else if (rightSibling != null) { // Merging with the right sibling... for (int index = rightSiblingChildren.Items.Count; index-- > 0;) { int itemIndex = 0; PdfDirectObject item = rightSiblingChildren.Items[itemIndex]; rightSiblingChildren.Items.RemoveAt(itemIndex); kidChildren.Items.Add(item); } nodeChildren.Items.RemoveAt(mid + 1); rightSibling.Delete(); } if (nodeChildren.Items.Count == 1) { // Collapsing node... // Remove the lonely intermediate node from the parent! nodeChildren.Items.RemoveAt(0); if (node == BaseDataObject) // Root node [FIX:50]. { /* * NOTE: In case of root collapse, Kids entry must be converted to * key-value-pairs entry, as no more intermediate nodes are available. */ node[pairsKey] = node[PdfName.Kids]; node.Remove(PdfName.Kids); nodeChildren.TypeName = pairsKey; } // Populate the parent with the lonely intermediate node's children! for (int index = kidChildren.Items.Count; index-- > 0;) { const int RemovedItemIndex = 0; PdfDirectObject item = kidChildren.Items[RemovedItemIndex]; kidChildren.Items.RemoveAt(RemovedItemIndex); nodeChildren.Items.Add(item); } kid.Delete(); kid = node; kidReference = kid.Reference; kidChildren = nodeChildren; } } // Update key limits! UpdateNodeLimits(kidChildren); } // Go down one level! nodeReferenceStack.Push(kidReference); node = kid; break; } } } } }