示例#1
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;
                    }
                }
            }
        }
示例#2
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); }
        }
示例#3
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.Reference.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.Reference.Delete();
                                    }
                                    if (nodeChildren.Items.Count == 1)
                                    {
                                        // Collapsing root...
                                        nodeChildren.Items.RemoveAt(0);
                                        for (int index = kidChildren.Items.Count; index-- > 0;)
                                        {
                                            int             itemIndex = 0;
                                            PdfDirectObject item      = kidChildren.Items[itemIndex];
                                            kidChildren.Items.RemoveAt(itemIndex);
                                            nodeChildren.Items.Add(item);
                                        }
                                        kid.Reference.Delete();
                                        kid          = node;
                                        kidReference = kid.Reference;
                                        kidChildren  = nodeChildren;
                                    }
                                }
                                // Update key limits!
                                UpdateNodeLimits(kidChildren);
                            }
                            // Go down one level!
                            nodeReferenceStack.Push(kidReference);
                            node = kid;
                            break;
                        }
                    }
                }
            }
        }
示例#4
0
            private KeyValuePair <TKey, TValue>?GetNext(
                )
            {
                /*
                 * NOTE: Algorithm:
                 * 1. [Vertical, down] We have to go downward the name tree till we reach
                 * a names collection (leaf node).
                 * 2. [Horizontal] Then we iterate across the names collection.
                 * 3. [Vertical, up] When leaf-nodes scan is complete, we go upward solving
                 * parent nodes, repeating step 1.
                 */
                while (true)
                {
                    if (names == null)
                    {
                        if (kids == null ||
                            kids.Count == levelIndex) // Kids subtree complete.
                        {
                            if (levels.Count == 0)
                            {
                                return(null);
                            }

                            // 3. Go upward one level.
                            // Restore current level!
                            object[] level = levels.Pop();
                            container  = (PdfIndirectObject)level[0];
                            kids       = (PdfArray)level[1];
                            levelIndex = ((int)level[2]) + 1; // Next node (partially scanned level).
                        }
                        else // Kids subtree incomplete.
                        {
                            // 1. Go downward one level.
                            // Save current level!
                            levels.Push(new object[] { container, kids, levelIndex });

                            // Move downward!
                            PdfReference kidReference = (PdfReference)kids[levelIndex];
                            container = kidReference.IndirectObject;
                            PdfDictionary   kid        = (PdfDictionary)kidReference.DataObject;
                            PdfDirectObject kidsObject = kid[PdfName.Kids];
                            if (kidsObject == null) // Leaf node.
                            {
                                PdfDirectObject namesObject = kid[PdfName.Names];
                                if (namesObject is PdfReference)
                                {
                                    container = ((PdfReference)namesObject).IndirectObject;
                                }
                                names = (PdfArray)namesObject.Resolve();
                                kids  = null;
                            }
                            else // Intermediate node.
                            {
                                if (kidsObject is PdfReference)
                                {
                                    container = ((PdfReference)kidsObject).IndirectObject;
                                }
                                kids = (PdfArray)kidsObject.Resolve();
                            }
                            levelIndex = 0; // First node (new level).
                        }
                    }
                    else
                    {
                        if (names.Count == levelIndex) // Names complete.
                        {
                            names = null;
                        }
                        else // Names incomplete.
                        {
                            // 2. Object found.
                            TKey   key   = (TKey)names[levelIndex];
                            TValue value = tree.WrapValue(names[levelIndex + 1]);
                            levelIndex += 2;

                            return(new KeyValuePair <TKey, TValue>(key, value));
                        }
                    }
                }
            }
示例#5
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="node">Current node.</param>
         */
        private void Add(
            PdfString key,
            TValue value,
            bool overwrite,
            PdfDictionary node
            )
        {
            PdfArray children = (PdfArray)File.Resolve(node[PdfName.Names]);

            if (children == null) // Intermediate node.
            {
                children = (PdfArray)File.Resolve(node[PdfName.Kids]);
                int low = 0, high = children.Count - 1;
                while (true)
                {
                    bool          matched = false;
                    int           mid     = (low + high) / 2;
                    PdfDictionary kid     = (PdfDictionary)File.Resolve(children[mid]);
                    PdfArray      limits  = (PdfArray)File.Resolve(kid[PdfName.Limits]);
                    if (key.CompareTo((PdfString)limits[0]) < 0) // Before the lower limit.
                    {
                        high = mid - 1;
                    }
                    else if (key.CompareTo((PdfString)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.
                    {
                        PdfName  kidChildrenTypeName;
                        int      kidChildrenOrder;
                        PdfArray kidChildren = GetChildren(kid, out kidChildrenTypeName, out kidChildrenOrder);
                        if (kidChildren.Count >= kidChildrenOrder) // Current node is full.
                        {
                            // Split the node!
                            SplitFullNode(
                                children,
                                mid,
                                kidChildrenTypeName
                                );
                            // Is the key before the splitted node?
                            if (key.CompareTo(((PdfArray)File.Resolve(kid[PdfName.Limits]))[0]) < 0)
                            {
                                kid = (PdfDictionary)File.Resolve(children[mid]);
                            }
                        }

                        Add(
                            key,
                            value,
                            overwrite,
                            kid
                            );
                        // Update the key limits!
                        UpdateNodeLimits(
                            node,
                            children,
                            PdfName.Kids
                            );
                        break;
                    }
                }
            }
            else // Leaf node.
            {
                int childrenCount = children.Count;
                int low = 0, high = childrenCount;
                while (true)
                {
                    int mid = (mid = ((low + high) / 2)) - (mid % 2);
                    if (mid >= childrenCount)
                    {
                        // Append the entry!
                        children.Add(key);
                        children.Add(value.BaseObject);
                        break;
                    }

                    int comparison = key.CompareTo(
                        (PdfString)children[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[mid]   = key;
                        children[++mid] = value.BaseObject;
                        break;
                    }
                    if (low > high)
                    {
                        // Insert the entry!
                        children.Insert(low, key);
                        children.Insert(++low, value.BaseObject);
                        break;
                    }
                }
                // Update the key limits!
                UpdateNodeLimits(
                    node,
                    children,
                    PdfName.Names
                    );
            }
        }
示例#6
0
        public TValue this[
            PdfString key
        ]
        {
            get
            {
                PdfDirectObject containerObject = BaseObject;
                PdfDictionary   parent          = BaseDataObject;
                while (true)
                {
                    PdfDirectObject namesObject = parent[PdfName.Names];
                    if (namesObject == null) // Intermediate node.
                    {
                        PdfArray kids = (PdfArray)File.Resolve(parent[PdfName.Kids]);
                        int      low = 0, high = kids.Count - 1;
                        while (true)
                        {
                            if (low > high)
                            {
                                return(null);
                            }

                            int             mid       = (low + high) / 2;
                            PdfDirectObject kidObject = kids[mid];
                            PdfDictionary   kid       = (PdfDictionary)File.Resolve(kidObject);
                            PdfArray        limits    = (PdfArray)File.Resolve(kid[PdfName.Limits]);
                            // Compare to the lower limit!
                            int comparison = key.CompareTo(
                                (PdfString)limits[0]
                                );
                            if (comparison < 0)
                            {
                                high = mid - 1;
                            }
                            else
                            {
                                // Compare to the upper limit!
                                comparison = key.CompareTo(
                                    (PdfString)limits[1]
                                    );
                                if (comparison > 0)
                                {
                                    low = mid + 1;
                                }
                                else
                                {
                                    // Go down one level!
                                    containerObject = kidObject; // NOTE: Node children MUST be indirectly referenced.
                                    parent          = kid;
                                    break;
                                }
                            }
                        }
                    }
                    else // Leaf node.
                    {
                        if (namesObject is PdfReference)
                        {
                            containerObject = namesObject;
                        }

                        PdfArray names = (PdfArray)File.Resolve(namesObject);
                        int      low = 0, high = names.Count;
                        while (true)
                        {
                            if (low > high)
                            {
                                return(null);
                            }

                            int mid        = (mid = ((low + high) / 2)) - (mid % 2);
                            int comparison = key.CompareTo(
                                (PdfString)names[mid]
                                );
                            if (comparison < 0)
                            {
                                high = mid - 2;
                            }
                            else if (comparison > 0)
                            {
                                low = mid + 2;
                            }
                            else
                            {
                                // We got it!
                                return(Wrap(
                                           names[mid + 1],
                                           ((PdfReference)containerObject).IndirectObject,
                                           (PdfString)names[mid]
                                           ));
                            }
                        }
                    }
                }
            }
            set
            { Add(key, value, true); }
        }