Exemplo n.º 1
0
        /**
          <param name="file">Associated file.</param>
          <param name="dataObject">
        <para>Data object associated to the indirect object. It MUST be</para>
        <list type="bullet">
          <item><code>null</code>, if the indirect object is original or free.</item>
          <item>NOT <code>null</code>, if the indirect object is new and in-use.</item>
        </list>
          </param>
          <param name="xrefEntry">Cross-reference entry associated to the indirect object. If the
        indirect object is new, its offset field MUST be set to 0.</param>
        */
        internal PdfIndirectObject(
      File file,
      PdfDataObject dataObject,
      XRefEntry xrefEntry
      )
        {
            this.file = file;
              this.dataObject = Include(dataObject);
              this.xrefEntry = xrefEntry;

              this.original = (xrefEntry.Offset >= 0);
              this.reference = new PdfReference(this);
        }
Exemplo n.º 2
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);
        }
Exemplo n.º 3
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;
              {
            // 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);
        }
Exemplo n.º 4
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>
          <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;
        }
Exemplo n.º 5
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;
              {
            // 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);
        }
Exemplo n.º 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);
        }
Exemplo n.º 7
0
        /**
         * <summary>Adds an indirect object entry to the specified xref stream.</summary>
         * <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(
            PdfIndirectObject indirectObject,
            XRefStream xrefStream,
            XRefEntry prevFreeEntry,
            IDictionary <int, ObjectStream> extensionObjectStreams
            )
        {
            XRefEntry xrefEntry = indirectObject.XrefEntry;

            // Add the entry to the xref stream!
            xrefStream[xrefEntry.Number] = xrefEntry;

            // Serialize the entry contents!
            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);
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
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); }
        }
Exemplo n.º 10
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); }
        }