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

            // 2. Body [PDF:1.6:3.4.2].
            int           xrefSize    = file.IndirectObjects.Count;
            StringBuilder xrefBuilder = new StringBuilder(XRefChunk);
            {
                /*
                 * NOTE: A standard xref table comprises just one section composed by just one subsection.
                 * NOTE: As xref-table free entries MUST be arrayed as a linked list,
                 * it's needed to cache intermingled in-use entries in order to properly render
                 * the object number of the next free entry inside the previous one.
                 */
                AppendXRefSubsectionIndexer(xrefBuilder, 0, xrefSize);

                StringBuilder   xrefInUseBlockBuilder = new StringBuilder();
                IndirectObjects indirectObjects       = file.IndirectObjects;
                PdfReference    freeReference         = indirectObjects[0].Reference; // Initialized to the first free entry.
                for (int index = 1; index < xrefSize; index++)
                {
                    // Current entry insertion.
                    PdfIndirectObject indirectObject = indirectObjects[index];
                    if (indirectObject.IsInUse()) // In-use entry.
                    {
                        // Add in-use entry!
                        AppendXRefEntry(xrefInUseBlockBuilder, indirectObject.Reference, stream.Length);
                        // Add in-use entry content!
                        indirectObject.WriteTo(stream, file);
                    }
                    else // Free entry.
                    {
                        // Add free entry!
                        AppendXRefEntry(xrefBuilder, freeReference, index);

                        // End current block!
                        xrefBuilder.Append(xrefInUseBlockBuilder);

                        // Initialize next block!
                        xrefInUseBlockBuilder.Length = 0;
                        freeReference = indirectObject.Reference;
                    }
                }
                // Add last free entry!
                AppendXRefEntry(xrefBuilder, freeReference, 0);

                // End last block!
                xrefBuilder.Append(xrefInUseBlockBuilder);
            }

            // 3. XRef table (unique section) [PDF:1.6:3.4.3].
            long startxref = stream.Length;

            stream.Write(xrefBuilder.ToString());

            // 4. Trailer [PDF:1.6:3.4.4].
            WriteTrailer(startxref, xrefSize, null);
        }
Esempio n. 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);
        }
        /**
         * <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);
        }