protected override void WriteStandard(
            )
        {
            // 1. Header [PDF:1.6:3.4.1].
            WriteHeader();

            // 2. Body [PDF:1.6:3.4.2,3,7].
            XRefEntry xrefStreamEntry;

            {
                // 2.1. Content indirect objects.
                IndirectObjects indirectObjects = file.IndirectObjects;

                // Create the xref stream indirect object!

                /*
                 * NOTE: Standard xref information structure comprises just one section; the xref stream is
                 * generated on-the-fly and kept volatile not to interfere with the existing file structure.
                 */
                /*
                 * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into the
                 * file's indirect objects collection).
                 */
                XRefStream xrefStream = new XRefStream(file);
                new PdfIndirectObject(
                    file,
                    xrefStream,
                    xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0)
                    );

                XRefEntry prevFreeEntry = null;
                foreach (PdfIndirectObject indirectObject in indirectObjects)
                {
                    prevFreeEntry = AddXRefEntry(
                        indirectObject.XrefEntry,
                        indirectObject,
                        xrefStream,
                        prevFreeEntry,
                        null
                        );
                }
                prevFreeEntry.Offset = 0; // Links back to the first free object. NOTE: The first entry in the table (object number 0) is always free.

                // 2.2. XRef stream.
                UpdateTrailer(xrefStream.Header, stream);
                AddXRefEntry(
                    xrefStreamEntry,
                    xrefStream.Container,
                    xrefStream,
                    null,
                    null
                    );
            }

            // 3. Tail.
            WriteTail(xrefStreamEntry.Offset);
        }
Exemple #2
0
        /**
         * <summary>Adds an indirect object entry to the specified xref stream.</summary>
         * <param name="xrefEntry">Indirect object's xref entry.</param>
         * <param name="indirectObject">Indirect object.</param>
         * <param name="xrefStream">XRef stream.</param>
         * <param name="prevFreeEntry">Previous free xref entry.</param>
         * <returns>Current free xref entry.</returns>
         */
        private XRefEntry AddXRefEntry(
            XRefEntry xrefEntry,
            PdfIndirectObject indirectObject,
            XRefStream xrefStream,
            XRefEntry prevFreeEntry
            )
        {
            xrefStream[xrefEntry.Number] = xrefEntry;

            switch (xrefEntry.Usage)
            {
            case XRefEntry.UsageEnum.InUse:
                // Set entry content's offset!
                xrefEntry.Offset = (int)stream.Length;
                // Add entry content!
                indirectObject.WriteTo(stream);
                break;

            case XRefEntry.UsageEnum.InUseCompressed:
                /* NOOP: Serialization is delegated to the containing object stream. */
                break;

            case XRefEntry.UsageEnum.Free:
                if (prevFreeEntry != null)
                {
                    prevFreeEntry.Offset = xrefEntry.Number;
                }                                    // Object number of the next free object.

                prevFreeEntry = xrefEntry;
                break;

            default:
                throw new NotSupportedException();
            }
            return(prevFreeEntry);
        }
Exemple #3
0
        /**
         * <summary>Retrieves the file information.</summary>
         */
        public FileInfo ReadInfo(
            )
        {
            //TODO:hybrid xref table/stream
            Version       version = Version.Get(parser.RetrieveVersion());
            PdfDictionary trailer = null;
            SortedDictionary <int, XRefEntry> xrefEntries = new SortedDictionary <int, XRefEntry>();

            {
                long sectionOffset = parser.RetrieveXRefOffset();
                while (sectionOffset > -1)
                {
                    // Move to the start of the xref section!
                    parser.Seek(sectionOffset);

                    PdfDictionary sectionTrailer;
                    if (parser.GetToken(1).Equals(Keyword.XRef)) // XRef-table section.
                    {
                        // Looping sequentially across the subsections inside the current xref-table section...
                        while (true)
                        {
                            /*
                             * NOTE: Each iteration of this block represents the scanning of one subsection.
                             * We get its bounds (first and last object numbers within its range) and then collect
                             * its entries.
                             */
                            // 1. First object number.
                            parser.MoveNext();
                            if ((parser.TokenType == PostScriptParser.TokenTypeEnum.Keyword) &&
                                parser.Token.Equals(Keyword.Trailer)) // XRef-table section ended.
                            {
                                break;
                            }
                            else if (parser.TokenType != PostScriptParser.TokenTypeEnum.Integer)
                            {
                                throw new ParseException("Neither object number of the first object in this xref subsection nor end of xref section found.", parser.Position);
                            }

                            // Get the object number of the first object in this xref-table subsection!
                            int startObjectNumber = (int)parser.Token;

                            // 2. Last object number.
                            parser.MoveNext();
                            if (parser.TokenType != PostScriptParser.TokenTypeEnum.Integer)
                            {
                                throw new ParseException("Number of entries in this xref subsection not found.", parser.Position);
                            }

                            // Get the object number of the last object in this xref-table subsection!
                            int endObjectNumber = (int)parser.Token + startObjectNumber;

                            // 3. XRef-table subsection entries.
                            for (
                                int index = startObjectNumber;
                                index < endObjectNumber;
                                index++
                                )
                            {
                                if (xrefEntries.ContainsKey(index)) // Already-defined entry.
                                {
                                    // Skip to the next entry!
                                    parser.MoveNext(3);
                                    continue;
                                }

                                // Get the indirect object offset!
                                int offset = (int)parser.GetToken(1);
                                // Get the object generation number!
                                int generation = (int)parser.GetToken(1);
                                // Get the usage tag!
                                XRefEntry.UsageEnum usage;
                                {
                                    string usageToken = (string)parser.GetToken(1);
                                    if (usageToken.Equals(Keyword.InUseXrefEntry))
                                    {
                                        usage = XRefEntry.UsageEnum.InUse;
                                    }
                                    else if (usageToken.Equals(Keyword.FreeXrefEntry))
                                    {
                                        usage = XRefEntry.UsageEnum.Free;
                                    }
                                    else
                                    {
                                        throw new ParseException("Invalid xref entry.", parser.Position);
                                    }
                                }

                                // Define entry!
                                xrefEntries[index] = new XRefEntry(
                                    index,
                                    generation,
                                    offset,
                                    usage
                                    );
                            }
                        }

                        // Get the previous trailer!
                        sectionTrailer = (PdfDictionary)parser.ParsePdfObject(1);
                    }
                    else // XRef-stream section.
                    {
                        XRefStream stream = (XRefStream)parser.ParsePdfObject(3); // Gets the xref stream skipping the indirect-object header.
                        // XRef-stream subsection entries.
                        foreach (XRefEntry xrefEntry in stream.Values)
                        {
                            if (xrefEntries.ContainsKey(xrefEntry.Number)) // Already-defined entry.
                            {
                                continue;
                            }

                            // Define entry!
                            xrefEntries[xrefEntry.Number] = xrefEntry;
                        }

                        // Get the previous trailer!
                        sectionTrailer = stream.Header;
                    }

                    if (trailer == null)
                    {
                        trailer = sectionTrailer;
                    }

                    // Get the previous xref-table section's offset!
                    PdfInteger prevXRefOffset = (PdfInteger)sectionTrailer[PdfName.Prev];
                    sectionOffset = (prevXRefOffset != null ? prevXRefOffset.IntValue : -1);
                }
            }
            return(new FileInfo(version, trailer, xrefEntries));
        }
        protected override void WriteIncremental(
            )
        {
            // 1. Original content (header, body and previous trailer).
            FileParser parser = file.Reader.Parser;

            stream.Write(parser.Stream);

            // 2. Body update (modified indirect objects insertion).
            XRefEntry xrefStreamEntry;

            {
                // 2.1. Content indirect objects.
                IndirectObjects indirectObjects = file.IndirectObjects;

                // Create the xref stream!

                /*
                 * NOTE: Incremental xref information structure comprises multiple sections; this update adds
                 * a new section.
                 */
                XRefStream xrefStream = new XRefStream(file);

                XRefEntry prevFreeEntry = null;

                /*
                 * NOTE: Extension object streams are necessary to update original object streams whose
                 * entries have been modified.
                 */
                IDictionary <int, ObjectStream> extensionObjectStreams = new Dictionary <int, ObjectStream>();
                foreach (PdfIndirectObject indirectObject in new List <PdfIndirectObject>(indirectObjects.ModifiedObjects.Values))
                {
                    prevFreeEntry = AddXRefEntry(
                        indirectObject.XrefEntry,
                        indirectObject,
                        xrefStream,
                        prevFreeEntry,
                        extensionObjectStreams
                        );
                }
                foreach (ObjectStream extensionObjectStream in extensionObjectStreams.Values)
                {
                    prevFreeEntry = AddXRefEntry(
                        extensionObjectStream.Container.XrefEntry,
                        extensionObjectStream.Container,
                        xrefStream,
                        prevFreeEntry,
                        null
                        );
                }
                if (prevFreeEntry != null)
                {
                    prevFreeEntry.Offset = 0;
                }                   // Links back to the first free object. NOTE: The first entry in the table (object number 0) is always free.

                // 2.2. XRef stream.

                /*
                 * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into the
                 * file's indirect objects collection).
                 */
                new PdfIndirectObject(
                    file,
                    xrefStream,
                    xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0)
                    );
                UpdateTrailer(xrefStream.Header, stream);
                xrefStream.Header[PdfName.Prev] = PdfInteger.Get((int)parser.RetrieveXRefOffset());
                AddXRefEntry(
                    xrefStreamEntry,
                    xrefStream.Container,
                    xrefStream,
                    null,
                    null
                    );
            }

            // 3. Tail.
            WriteTail(xrefStreamEntry.Offset);
        }
        /**
         * <summary>Adds an indirect object entry to the specified xref stream.</summary>
         * <param name="xrefEntry">Indirect object's xref entry.</param>
         * <param name="indirectObject">Indirect object.</param>
         * <param name="xrefStream">XRef stream.</param>
         * <param name="prevFreeEntry">Previous free xref entry.</param>
         * <param name="extensionObjectStreams">Object streams used in incremental updates to extend
         *  modified ones.</param>
         * <returns>Current free xref entry.</returns>
         */
        private XRefEntry AddXRefEntry(
            XRefEntry xrefEntry,
            PdfIndirectObject indirectObject,
            XRefStream xrefStream,
            XRefEntry prevFreeEntry,
            IDictionary <int, ObjectStream> extensionObjectStreams
            )
        {
            xrefStream[xrefEntry.Number] = xrefEntry;

            switch (xrefEntry.Usage)
            {
            case XRefEntry.UsageEnum.InUse:
            {
                int offset = (int)stream.Length;
                // Add entry content!
                indirectObject.WriteTo(stream, file);
                // Set entry content's offset!
                xrefEntry.Offset = offset;
            }
            break;

            case XRefEntry.UsageEnum.InUseCompressed:
                /*
                 * NOTE: Serialization is delegated to the containing object stream.
                 */
                if (extensionObjectStreams != null) // Incremental update.
                {
                    int baseStreamNumber = xrefEntry.StreamNumber;
                    PdfIndirectObject baseStreamIndirectObject = file.IndirectObjects[baseStreamNumber];
                    if (baseStreamIndirectObject.IsOriginal()) // Extension stream needed in order to preserve the original object stream.
                    {
                        // Get the extension object stream associated to the original object stream!
                        ObjectStream extensionObjectStream;
                        if (!extensionObjectStreams.TryGetValue(baseStreamNumber, out extensionObjectStream))
                        {
                            file.Register(extensionObjectStream = new ObjectStream());
                            // Link the extension to the base object stream!
                            extensionObjectStream.BaseStream         = (ObjectStream)baseStreamIndirectObject.DataObject;
                            extensionObjectStreams[baseStreamNumber] = extensionObjectStream;
                        }
                        // Insert the data object into the extension object stream!
                        extensionObjectStream[xrefEntry.Number] = indirectObject.DataObject;
                        // Update the data object's xref entry!
                        xrefEntry.StreamNumber = extensionObjectStream.Reference.ObjectNumber;
                        xrefEntry.Offset       = XRefEntry.UndefinedOffset; // Internal object index unknown (to set on object stream serialization -- see ObjectStream).
                    }
                }
                break;

            case XRefEntry.UsageEnum.Free:
                if (prevFreeEntry != null)
                {
                    prevFreeEntry.Offset = xrefEntry.Number;
                }                                    // Object number of the next free object.

                prevFreeEntry = xrefEntry;
                break;

            default:
                throw new NotSupportedException();
            }
            return(prevFreeEntry);
        }
Exemple #6
0
        protected override void WriteIncremental(
            )
        {
            // 1. Original content (header, body and previous trailer).
            FileParser parser = file.Reader.Parser;

            stream.Write(parser.Stream);

            // 2. Body update (modified indirect objects insertion).
            XRefEntry xrefStreamEntry;

            {
                // Create the xref stream!

                /*
                 * NOTE: Incremental xref information structure comprises multiple sections; this update adds
                 * a new section.
                 */
                XRefStream xrefStream = new XRefStream(file);

                // 2.1. Indirect objects.
                IndirectObjects indirectObjects = file.IndirectObjects;

                // 2.1.1. Modified indirect objects serialization.
                XRefEntry prevFreeEntry = null;

                /*
                 * NOTE: Any uncompressed indirect object will be compressed.
                 */
                ObjectStream objectStream = null;

                /*
                 * NOTE: Any previously-compressed indirect object will have its original object stream
                 * updated through a new extension object stream.
                 */
                IDictionary <int, ObjectStream> extensionObjectStreams = new Dictionary <int, ObjectStream>();
                int indirectObjectsPrecompressCount = indirectObjects.Count;
                foreach (PdfIndirectObject indirectObject in new List <PdfIndirectObject>(indirectObjects.ModifiedObjects.Values))
                {
                    if (indirectObject.IsCompressible())
                    {
                        if (objectStream == null ||
                            objectStream.Count >= ObjectStreamMaxEntryCount)
                        {
                            file.Register(objectStream = new ObjectStream());
                        }

                        indirectObject.Compress(objectStream);
                    }

                    prevFreeEntry = AddXRefEntry(
                        indirectObject,
                        xrefStream,
                        prevFreeEntry,
                        extensionObjectStreams
                        );
                }
                // 2.1.2. Additional object streams serialization.
                for (int index = indirectObjectsPrecompressCount, limit = indirectObjects.Count; index < limit; index++)
                {
                    prevFreeEntry = AddXRefEntry(
                        indirectObjects[index],
                        xrefStream,
                        prevFreeEntry,
                        null
                        );
                }
                if (prevFreeEntry != null)
                {
                    prevFreeEntry.Offset = 0; // Links back to the first free object. NOTE: The first entry in the table (object number 0) is always free.
                }

                // 2.2. XRef stream.
                UpdateTrailer(xrefStream.Header, stream);
                xrefStream.Header[PdfName.Prev] = PdfInteger.Get((int)parser.RetrieveXRefOffset());
                AddXRefEntry(

                    /*
                     * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into
                     * the file's indirect objects collection).
                     */
                    new PdfIndirectObject(
                        file,
                        xrefStream,
                        xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0, (int)stream.Length, XRefEntry.UsageEnum.InUse)
                        ),
                    xrefStream,
                    null,
                    null
                    );
            }

            // 3. Tail.
            WriteTail(xrefStreamEntry.Offset);
        }
Exemple #7
0
        protected override void WriteStandard(
            )
        {
            // 1. Header [PDF:1.6:3.4.1].
            WriteHeader();

            // 2. Body [PDF:1.6:3.4.2,3,7].
            XRefEntry xrefStreamEntry;

            {
                // Create the xref stream!

                /*
                 * NOTE: Standard xref information structure comprises just one section; the xref stream is
                 * generated on-the-fly and kept volatile not to interfere with the existing file structure.
                 */
                XRefStream xrefStream = new XRefStream(file);

                // 2.1. Indirect objects.
                IndirectObjects indirectObjects = file.IndirectObjects;

                // Indirect objects serialization.
                XRefEntry    prevFreeEntry = null;
                ObjectStream objectStream  = null;
                foreach (PdfIndirectObject indirectObject in indirectObjects)
                {
                    if (indirectObject.IsCompressible())
                    {
                        if (objectStream == null ||
                            objectStream.Count >= ObjectStreamMaxEntryCount)
                        {
                            file.Register(objectStream = new ObjectStream());
                        }

                        indirectObject.Compress(objectStream);
                    }

                    prevFreeEntry = AddXRefEntry(
                        indirectObject,
                        xrefStream,
                        prevFreeEntry,
                        null
                        );
                }
                prevFreeEntry.Offset = 0; // Links back to the first free object. NOTE: The first entry in the table (object number 0) is always free.

                // 2.2. XRef stream.
                UpdateTrailer(xrefStream.Header, stream);
                AddXRefEntry(

                    /*
                     * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into
                     * the file's indirect objects collection).
                     */
                    new PdfIndirectObject(
                        file,
                        xrefStream,
                        xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0, (int)stream.Length, XRefEntry.UsageEnum.InUse)
                        ),
                    xrefStream,
                    null,
                    null
                    );
            }

            // 3. Tail.
            WriteTail(xrefStreamEntry.Offset);
        }
Exemple #8
0
        protected override void WriteIncremental(
            )
        {
            try
            {
                // 1. Original content (head, body and previous trailer).
                Parser parser = file.Reader.Parser;
                stream.Write(parser.Stream);

                // 2. Body update (modified indirect objects insertion).
                XRefEntry xrefStreamEntry;
                {
                    // 2.1. Content indirect objects.
                    IndirectObjects indirectObjects = file.IndirectObjects;

                    // Create the xref stream indirect object!

                    /*
                     * NOTE: Incremental xref table comprises multiple sections each one composed by multiple subsections;
                     * this update adds a new section.
                     */
                    /*
                     * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into the file's
                     * indirect objects collection).
                     */
                    XRefStream        xrefStream;
                    PdfIndirectObject xrefStreamIndirectObject = new PdfIndirectObject(
                        file,
                        xrefStream      = new XRefStream(file),
                        xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0, 0, XRefEntry.UsageEnum.InUse)
                        );

                    XRefEntry prevFreeEntry = null;
                    foreach (PdfIndirectObject indirectObject in indirectObjects.ModifiedObjects.Values)
                    {
                        prevFreeEntry = AddXRefEntry(
                            indirectObject.XrefEntry,
                            indirectObject,
                            xrefStream,
                            prevFreeEntry
                            );
                    }
                    if (prevFreeEntry != null)
                    {
                        prevFreeEntry.Offset = 0;
                    }                 // Linking back to the first free object. NOTE: The first entry in the table (object number 0) is always free.

                    // 2.2. XRef stream.
                    xrefStream.Header[PdfName.Prev] = new PdfInteger((int)parser.RetrieveXRefOffset());
                    AddXRefEntry(
                        xrefStreamEntry,
                        xrefStreamIndirectObject,
                        xrefStream,
                        null
                        );
                }

                // 3. Tail.
                WriteTail(xrefStreamEntry.Offset);
            }
            catch (Exception e)
            { throw new Exception("Incremental writing failed.", e); }
        }
Exemple #9
0
        protected override void WriteStandard(
            )
        {
            try
            {
                // 1. Header [PDF:1.6:3.4.1].
                WriteHeader();

                // 2. Body [PDF:1.6:3.4.2,3,7].
                XRefEntry xrefStreamEntry;
                {
                    // 2.1. Content indirect objects.
                    IndirectObjects indirectObjects = file.IndirectObjects;

                    // Create the xref stream indirect object!

                    /*
                     * NOTE: A standard xref stream comprises just one section composed by just one subsection.
                     * The xref stream is generated on-the-fly and kept volatile not to interfere with the existing
                     * file structure.
                     */
                    /*
                     * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into the file's
                     * indirect objects collection).
                     */
                    XRefStream        xrefStream;
                    PdfIndirectObject xrefStreamIndirectObject = new PdfIndirectObject(
                        file,
                        xrefStream      = new XRefStream(file),
                        xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0, 0, XRefEntry.UsageEnum.InUse)
                        );

                    XRefEntry prevFreeEntry = null;
                    foreach (PdfIndirectObject indirectObject in indirectObjects)
                    {
                        PdfIndirectObject actualIndirectObject;
                        if (indirectObject.DataObject is XRefStream)
                        {
                            /*
                             * NOTE: Existing xref streams MUST be suppressed,
                             * temporarily replacing them with free entries.
                             */
                            actualIndirectObject = new PdfIndirectObject(
                                file,
                                null,
                                new XRefEntry(
                                    indirectObject.Reference.ObjectNumber,
                                    XRefEntry.GenerationUnreusable,
                                    0,
                                    XRefEntry.UsageEnum.Free
                                    )
                                );
                        }
                        else
                        {
                            actualIndirectObject = indirectObject;
                        }

                        prevFreeEntry = AddXRefEntry(
                            (XRefEntry)actualIndirectObject.XrefEntry.Clone(), // NOTE: Xref entry is cloned to preserve the original one.
                            actualIndirectObject,
                            xrefStream,
                            prevFreeEntry
                            );
                    }
                    prevFreeEntry.Offset = 0; // Linking back to the first free object. NOTE: The first entry in the table (object number 0) is always free.

                    // 2.2. XRef stream.
                    AddXRefEntry(
                        xrefStreamEntry,
                        xrefStreamIndirectObject,
                        xrefStream,
                        null
                        );
                }

                // 3. Tail.
                WriteTail(xrefStreamEntry.Offset);
            }
            catch (Exception e)
            { throw new Exception("Standard writing failed.", e); }
        }