Example #1
0
        /**
         * <summary>Removes all the given node's children.</summary>
         * <remarks>
         *  <para>As this method doesn't apply balancing, it's suitable for clearing root nodes only.
         *  </para>
         *  <para>Removal affects only tree nodes: referenced objects are preserved to avoid inadvertently
         *  breaking possible references to them from somewhere else.</para>
         * </remarks>
         * <param name="node">Current node.</param>
         */
        private void Clear(
            PdfDictionary node
            )
        {
            Children children = Children.Get(node, pairsKey);

            if (!children.IsLeaf())
            {
                foreach (PdfDirectObject child in children.Items)
                {
                    Clear((PdfDictionary)child.Resolve());
                    File.Unregister((PdfReference)child);
                }
                node[pairsKey] = node[children.TypeName];
                node.Remove(children.TypeName); // Recycles the array as the intermediate node transforms to leaf.
            }
            children.Items.Clear();
            node.Remove(PdfName.Limits);
        }
Example #2
0
        /**
         * <summary>Removes all the given node's children.</summary>
         * <remarks>Removal affects only tree nodes: referenced objects are preserved
         * to avoid inadvertently breaking possible references to them from somewhere else.</remarks>
         * <param name="node">Current node.</param>
         */
        private void Clear(
            PdfDictionary node
            )
        {
            PdfName  childrenTypeName;
            int      childrenOrder;
            PdfArray children = GetChildren(node, out childrenTypeName, out childrenOrder);

            if (childrenTypeName.Equals(PdfName.Kids))
            {
                foreach (PdfDirectObject child in children)
                {
                    Clear((PdfDictionary)File.Resolve(child));
                    File.Unregister((PdfReference)child);
                }

                node[PdfName.Names] = node[childrenTypeName];
                node.Remove(childrenTypeName);
            }
            children.Clear();
            node.Remove(PdfName.Limits);
        }
        /**
         * <param name="preserve">Indicates whether the data from the old data source substitutes the
         * new one. This way data can be imported to/exported from local or preserved in case of external
         * file location changed.</param>
         * <seealso cref="DataFile"/>
         */
        public void SetDataFile(
            FileSpecification value,
            bool preserve
            )
        {
            /*
             * NOTE: If preserve argument is set to true, body's dirtiness MUST be forced in order to ensure
             * data serialization to the new external location.
             *
             * Old data source | New data source | preserve | Action
             * ----------------------------------------------------------------------------------------------
             * local           | not null        | false     | A. Substitute local with new file.
             * local           | not null        | true      | B. Export local to new file.
             * external        | not null        | false     | C. Substitute old file with new file.
             * external        | not null        | true      | D. Copy old file data to new file.
             * local           | null            | (any)     | E. No action.
             * external        | null            | false     | F. Empty local.
             * external        | null            | true      | G. Import old file to local.
             * ----------------------------------------------------------------------------------------------
             */
            FileSpecification oldDataFile    = DataFile;
            PdfDirectObject   dataFileObject = (value != null ? value.BaseObject : null);

            if (value != null)
            {
                if (preserve)
                {
                    if (oldDataFile != null) // Case D (copy old file data to new file).
                    {
                        if (!bodyResolved)
                        {
                            // Transfer old file data to local!
                            GetBody(false); // Ensures that external data is loaded as-is into the local buffer.
                        }
                    }
                    else // Case B (export local to new file).
                    {
                        // Transfer local settings to file!
                        header[PdfName.FFilter]      = header[PdfName.Filter]; header.Remove(PdfName.Filter);
                        header[PdfName.FDecodeParms] = header[PdfName.DecodeParms]; header.Remove(PdfName.DecodeParms);

                        // Ensure local data represents actual data (otherwise it would be substituted by resolved file data)!
                        bodyResolved = true;
                    }
                    // Ensure local data has to be serialized to new file!
                    body.Dirty = true;
                }
                else // Case A/C (substitute local/old file with new file).
                {
                    // Dismiss local/old file data!
                    body.Clear();
                    // Dismiss local/old file settings!
                    Filter     = null;
                    Parameters = null;
                    // Ensure local data has to be loaded from new file!
                    bodyResolved = false;
                }
            }
            else
            {
                if (oldDataFile != null)
                {
                    if (preserve) // Case G (import old file to local).
                    {
                        // Transfer old file data to local!
                        GetBody(false); // Ensures that external data is loaded as-is into the local buffer.
                        // Transfer old file settings to local!
                        header[PdfName.Filter]      = header[PdfName.FFilter]; header.Remove(PdfName.FFilter);
                        header[PdfName.DecodeParms] = header[PdfName.FDecodeParms]; header.Remove(PdfName.FDecodeParms);
                    }
                    else // Case F (empty local).
                    {
                        // Dismiss old file data!
                        body.Clear();
                        // Dismiss old file settings!
                        Filter     = null;
                        Parameters = null;
                        // Ensure local data represents actual data (otherwise it would be substituted by resolved file data)!
                        bodyResolved = true;
                    }
                }
                else // E (no action).
                { /* NOOP */
                }
            }
            header[PdfName.F] = dataFileObject;
        }
Example #4
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;
                        }
                    }
                }
            }
        }