public TrailerPart ParseTrailer(PdfStreamReader streamReader, IPdf pdf) { var header = streamReader.ReadLine(); if (header != "trailer") { throw new ArgumentOutOfRangeException(nameof(streamReader), "First line in Trailer Content is not \"trailer\""); } var trailerDictionary = this._pdfReader.ReadObject(streamReader, pdf); if (!(trailerDictionary is PdfDictionary)) { throw new InvalidDataException("Trailer dictionary content was not a dictionary."); } var line = streamReader.ReadLine(); var foundCrossReference = false; if (line == "startxref") { foundCrossReference = true; } if (!foundCrossReference) { throw new InvalidDataException("Missing startxref line"); } var crossReferenceLine = streamReader.ReadLine(); if (!long.TryParse(crossReferenceLine, out var crossReferenceOffset)) { throw new InvalidDataException("Cross Reference Offset value is not a parseable number"); } line = streamReader.ReadLine(); if (line == null || line == "%%EOF") { var result = new TrailerPart((PdfDictionary)trailerDictionary, crossReferenceOffset); return(result); } throw new InvalidDataException("Trailer content is invalid, the last 2 lines should be startxref and a number and optionally a 3rd line containing %%EOF"); }
public VersionPart ReadPart(PdfStreamReader streamReader, IPdf pdf) { var line = streamReader.ReadLine(); if (line == null) { throw new ArgumentOutOfRangeException(nameof(streamReader), "Unexpected end of stream"); } else if (line.StartsWith(PdfVersionPrefix)) { var result = this.GetVersionPart(line); return(result); } else { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Expected content at current position was not a version"); } }
public CrossReferencePart ReadPart(PdfStreamReader streamReader, IPdf pdf) { if (pdf == null) { throw new ArgumentNullException(nameof(pdf)); } if (pdf.Trailer == null || pdf.Trailer.StartCrossReference == 0) { return(null); } var originalPosition = streamReader.Position; try { streamReader.Seek(pdf.Trailer.StartCrossReference, SeekOrigin.Begin); var line = streamReader.ReadLine(); if (line != "xref") { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid Cross Reference Header"); } var subsections = new List <CrossReferencePartSubSection>(); while (line == "xref") { subsections.Add(_subSectionReader.ReadPart(streamReader, pdf)); line = streamReader.ReadLine(); } var result = new CrossReferencePart { Sections = subsections.ToArray() }; return(result); } finally { streamReader.Seek(originalPosition, SeekOrigin.Begin); } }
public CrossReferencePartSubSectionEntry ReadPart(PdfStreamReader streamReader, IPdf pdf) { var line = streamReader.ReadLine(); if (line.Length != 18) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Line is not 18 characters long."); } var fields = line.Split(' '); if (fields.Length != 3) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Line does not have 3 fields."); } if (!long.TryParse(fields[0], out var offset)) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid offset field. Not a valid number."); } if (!int.TryParse(fields[1], out var generation)) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid generation field. Not a valid number."); } if (fields[2] != "f" && fields[2] != "n") { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid in use flag. Not 'n' or 'f'."); } var inUseFlag = (CrossReferenceEntryFlag)fields[2][0]; var result = new CrossReferencePartSubSectionEntry { Generation = generation, InUse = inUseFlag, Offset = offset }; return(result); }
public CrossReferencePartSubSection ReadPart(PdfStreamReader streamReader, IPdf pdf) { var line = streamReader.ReadLine(); var fields = line.Split(' '); if (fields.Length != 2) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid field count for subsection counts."); } if (!int.TryParse(fields[0], out var startingObject)) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid starting object field. Not a valid number."); } if (!int.TryParse(fields[1], out var objectCount)) { throw new ArgumentOutOfRangeException(nameof(streamReader), line, "Invalid object count. Not a valid number."); } var entries = new CrossReferencePartSubSectionEntry[objectCount]; for (var i = 0; i < entries.Length; i++) { var entry = this._partReader.ReadPart(streamReader, pdf); entry.ObjectNumber = startingObject + i; entries[i] = entry; } var result = new CrossReferencePartSubSection { Entries = entries, StartingObject = startingObject }; return(result); }
public IPdf Create(Stream stream, PdfOptions pdfOptions) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (!stream.CanSeek) { throw new InvalidDataException("The stream must be seekable"); } if (stream.Length == 0) { throw new InvalidDataException("Stream is 0 bytes."); } stream.Seek(0, SeekOrigin.Begin); var streamReader = new PdfStreamReader(stream, pdfOptions.ReadBlockSize); var pdf = new DefaultPdf(this._pdfReader, streamReader) { Options = pdfOptions }; pdf.Version = this._versionPartReader.ReadPart(streamReader, pdf); pdf.Trailer = this._trailerPartReader.ReadPart(streamReader, pdf); if (pdf.Version >= new Version(1, 4)) { //TODO: spec section 7.5.2 states that if the version in the first line is >= 1.4, use the version in the trailer if it exists } pdf.CrossReferenceTable = this._crossReferencePartReader.ReadPart(streamReader, pdf); if (pdf.Trailer.Encrypt != null) { PdfDictionary encryptDictionary; if (pdf.Trailer.Encrypt is PdfReference o) { var readObject = pdf.ReadIndirectObject(o); if (readObject == null) { throw new InvalidDataException("Missing encrypt object"); } if (!(readObject.InnerObject is PdfDictionary)) { throw new InvalidDataException("Encrypt object is not a pdf dictionary"); } encryptDictionary = (PdfDictionary)readObject.InnerObject; } else if (pdf.Trailer.Encrypt is PdfDictionary) { encryptDictionary = (PdfDictionary)pdf.Trailer.Encrypt; } else { throw new InvalidDataException("Invalid encrypt dictionary entry"); } pdf.EncryptionDictionary = new EncryptionDictionary(encryptDictionary); } return(pdf); }
public TrailerPart ReadPart(PdfStreamReader streamReader, IPdf pdf) { var currentPosition = streamReader.Position; try { var trailerBlockSize = 512; var block = new byte[trailerBlockSize]; int trailerStart; //we'll read x number of bytes at a time with a 7 byte overlap to account for the word trailer. //length = 1500 streamReader.Seek(-trailerBlockSize, SeekOrigin.End); string content; var foundTrailer = false; do { var loopPosition = streamReader.Position; streamReader.Read(block, 0, trailerBlockSize); content = Encoding.ASCII.GetString(block); if ((trailerStart = content.IndexOf("trailer")) >= 0) { streamReader.Seek(loopPosition + trailerStart, SeekOrigin.Begin); foundTrailer = true; break; } content = null; if (loopPosition == 0) { //we were at the beginning of the stream meaning we can't go back any more break; } if (streamReader.Position > trailerBlockSize) { streamReader.Seek((trailerBlockSize * -2) + 7, SeekOrigin.Current); //7 byte overlap } else { streamReader.Seek(0, SeekOrigin.Begin); } } while (streamReader.Position - trailerBlockSize > 0); //make sure we don't go before the beginning of the stream for files that have no trailer if (foundTrailer) { var result = ParseTrailer(streamReader, pdf); return(result); } return(null); } finally { // go back to where we were. streamReader.Seek(currentPosition, SeekOrigin.Begin); } }