Beispiel #1
0
        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());
                }
            }
        }
Beispiel #2
0
        /**
         * <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);
        }
Beispiel #3
0
        /**
         * <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);
            }
        }
Beispiel #4
0
        /**
         * <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);
        }
Beispiel #5
0
            /**
             * <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));
            }
Beispiel #6
0
        /**
         * <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;
                    }
                }
            }
        }
Beispiel #7
0
        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); }
        }
Beispiel #8
0
        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;
                        }
                    }
                }
            }
        }