public virtual PdfObject Visit( XRefStream obj, object data ) { return(obj); }
public override PdfObject Visit( XRefStream obj, object data ) { throw new NotSupportedException(); }
public virtual PdfObject Visit( XRefStream obj, object data ) { return obj; }
/// <summary> /// Creates a new instance of the PdfDocument class from the IO stream. /// </summary> /// <param name="stream">The <see cref="Stream"/> on which to open the PdfDocument.</param> /// <returns></returns> public static PdfDocument Open(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (!stream.CanRead) { throw new ArgumentException("Cannot read stream", nameof(stream)); } var document = new PdfDocument(stream); using (var reader = new PdfReader(stream)) { // Check header document.pdfVersion = PdfVersion.FromReader(reader); // Check trailer reader.Position = reader.GetXRefPosition(); // Read Cross-Reference Table IPdfTrailer trailer; IXRefSection xrefSection; char fisrtChar; do { fisrtChar = reader.Peek(); if (fisrtChar == XRefSection.StartKeyword[0]) { // Cross-Reference Section xrefSection = XRefSection.FromReader(reader); trailer = PdfTrailer.FromReader(reader); } else if (char.IsDigit(fisrtChar)) { // Cross-Reference Stream var xrefStream = XRefStream.FromReader(reader); trailer = xrefStream; xrefSection = xrefStream; } else { throw new FormatException("Invalid Cross-Reference section."); } if (document.xrefTable == null) { // Initialize document's Cross-Reference Table document.xrefTable = new XRefTable(xrefSection, trailer.Size); } else { // Register section document.xrefTable.AddSection(xrefSection); } // Keep instance of last trailer if (document.trailer == null) { document.trailer = trailer; } // Seek to previous trailer if (trailer.Prev.HasValue) { reader.Position = trailer.Prev.Value; } }while (trailer.Prev != null); } return(document); }
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; }
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); }