/// <summary> /// Reads the compressed object with the specified index. /// </summary> internal void ReadReferences(PdfCrossReferenceTable xrefTable) { ////// Create parser for stream. ////Parser parser = new Parser(_document, new MemoryStream(Stream.Value)); for (int idx = 0; idx < _header.Length; idx++) { int objectNumber = _header[idx][0]; int offset = _header[idx][1]; PdfObjectID objectID = new PdfObjectID(objectNumber); // HACK: -1 indicates compressed object. PdfReference iref = new PdfReference(objectID, -1); ////iref.ObjectID = objectID; ////iref.Value = xrefStream; if (!xrefTable.Contains(iref.ObjectID)) { xrefTable.Add(iref); } else { GetType(); } } }
/// <summary> /// Constructs the PdfTrailer from a document. /// </summary> /// <param name="parser">the parser used to read the file.</param> internal void ConstructFromDocument(Parser parser) { // TODO - May need to also search for encryption related trailer info PdfCrossReferenceTable xrefTable = _document._irefTable; Elements.SetInteger(Keys.Size, xrefTable.ObjectTable.Count); // find the root. PdfDictionary rootToUse = null; foreach (var reference in xrefTable.AllReferences) { PdfObject obj = parser.ReadObject(null, reference.ObjectID, false, false); if (obj is PdfDictionary dObj) { if (dObj.Elements[PdfCatalog.Keys.Type] as PdfName == "/Catalog") { if (rootToUse == null) { rootToUse = dObj; } else if (dObj.ObjectID.GenerationNumber > rootToUse.ObjectID.GenerationNumber) { rootToUse = dObj; } } } } if (rootToUse != null) { Elements.SetReference(Keys.Root, rootToUse); } }
/// <summary> /// Reads cross reference stream(s). /// </summary> private PdfTrailer ReadXRefStream(PdfCrossReferenceTable xrefTable) { // Read cross reference stream. //Debug.Assert(_lexer.Symbol == Symbol.Integer); int number = _lexer.TokenToInteger; int generation = ReadInteger(); Debug.Assert(generation == 0); ReadSymbol(Symbol.Obj); ReadSymbol(Symbol.BeginDictionary); PdfObjectID objectID = new PdfObjectID(number, generation); PdfCrossReferenceStream xrefStream = new PdfCrossReferenceStream(_document); ReadDictionary(xrefStream, false); ReadSymbol(Symbol.BeginStream); ReadStream(xrefStream); //xrefTable.Add(new PdfReference(objectID, position)); PdfReference iref = new PdfReference(xrefStream); iref.ObjectID = objectID; iref.Value = xrefStream; xrefTable.Add(iref); Debug.Assert(xrefStream.Stream != null); //string sValue = new RawEncoding().GetString(xrefStream.Stream.UnfilteredValue,); //sValue.GetType(); byte[] bytesRaw = xrefStream.Stream.UnfilteredValue; byte[] bytes = bytesRaw; // HACK: Should be done in UnfilteredValue. if (xrefStream.Stream.HasDecodeParams) { int predictor = xrefStream.Stream.DecodePredictor; int columns = xrefStream.Stream.DecodeColumns; bytes = DecodeCrossReferenceStream(bytesRaw, columns, predictor); } #if DEBUG_ for (int idx = 0; idx < bytes.Length; idx++) { if (idx % 4 == 0) Console.WriteLine(); Console.Write("{0:000} ", (int)bytes[idx]); } Console.WriteLine(); #endif // bytes.GetType(); // Add to table. // xrefTable.Add(new PdfReference(objectID, -1)); int size = xrefStream.Elements.GetInteger(PdfCrossReferenceStream.Keys.Size); PdfArray index = xrefStream.Elements.GetValue(PdfCrossReferenceStream.Keys.Index) as PdfArray; int prev = xrefStream.Elements.GetInteger(PdfCrossReferenceStream.Keys.Prev); PdfArray w = (PdfArray)xrefStream.Elements.GetValue(PdfCrossReferenceStream.Keys.W); // E.g.: W[1 2 1] ¤ Index[7 12] ¤ Size 19 // Setup subsections. int subsectionCount; int[][] subsections = null; int subsectionEntryCount = 0; if (index == null) { // Setup with default values. subsectionCount = 1; subsections = new int[subsectionCount][]; subsections[0] = new int[] { 0, size }; // HACK: What is size? Contratiction in PDF reference. subsectionEntryCount = size; } else { // Read subsections from array. Debug.Assert(index.Elements.Count % 2 == 0); subsectionCount = index.Elements.Count / 2; subsections = new int[subsectionCount][]; for (int idx = 0; idx < subsectionCount; idx++) { subsections[idx] = new int[] { index.Elements.GetInteger(2 * idx), index.Elements.GetInteger(2 * idx + 1) }; subsectionEntryCount += subsections[idx][1]; } } // W key. Debug.Assert(w.Elements.Count == 3); int[] wsize = { w.Elements.GetInteger(0), w.Elements.GetInteger(1), w.Elements.GetInteger(2) }; int wsum = StreamHelper.WSize(wsize); if (wsum * subsectionEntryCount != bytes.Length) GetType(); Debug.Assert(wsum * subsectionEntryCount == bytes.Length, "Check implementation here."); int testcount = subsections[0][1]; int[] currentSubsection = subsections[0]; #if DEBUG && CORE if (PdfDiagnostics.TraceXrefStreams) { for (int idx = 0; idx < testcount; idx++) { uint field1 = StreamHelper.ReadBytes(bytes, idx * wsum, wsize[0]); uint field2 = StreamHelper.ReadBytes(bytes, idx * wsum + wsize[0], wsize[1]); uint field3 = StreamHelper.ReadBytes(bytes, idx * wsum + wsize[0] + wsize[1], wsize[2]); string res = String.Format("{0,2:00}: {1} {2,5} {3} // ", idx, field1, field2, field3); switch (field1) { case 0: res += "Fee list: object number, generation number"; break; case 1: res += "Not compresed: offset, generation number"; break; case 2: res += "Compressed: object stream object number, index in stream"; break; default: res += "??? Type undefined"; break; } Debug.WriteLine(res); } } #endif int index2 = -1; for (int ssc = 0; ssc < subsectionCount; ssc++) { int abc = subsections[ssc][1]; for (int idx = 0; idx < abc; idx++) { index2++; PdfCrossReferenceStream.CrossReferenceStreamEntry item = new PdfCrossReferenceStream.CrossReferenceStreamEntry(); item.Type = StreamHelper.ReadBytes(bytes, index2 * wsum, wsize[0]); item.Field2 = StreamHelper.ReadBytes(bytes, index2 * wsum + wsize[0], wsize[1]); item.Field3 = StreamHelper.ReadBytes(bytes, index2 * wsum + wsize[0] + wsize[1], wsize[2]); xrefStream.Entries.Add(item); switch (item.Type) { case 0: // Nothing to do, not needed. break; case 1: // offset / generation number //// Even it is restricted, an object can exists in more than one subsection. //// (PDF Reference Implementation Notes 15). int position = (int)item.Field2; objectID = ReadObjectNumber(position); #if DEBUG if (objectID.ObjectNumber == 1074) GetType(); #endif Debug.Assert(objectID.GenerationNumber == item.Field3); //// Ignore the latter one. if (!xrefTable.Contains(objectID)) { #if DEBUG GetType(); #endif // Add iref for all uncrompressed objects. xrefTable.Add(new PdfReference(objectID, position)); } break; case 2: // Nothing to do yet. break; } } } return xrefStream; }
/// <summary> /// Reads cross reference table(s) and trailer(s). /// </summary> private PdfTrailer ReadXRefTableAndTrailer(PdfCrossReferenceTable xrefTable) { Debug.Assert(xrefTable != null); Symbol symbol = ScanNextToken(); if (symbol == Symbol.XRef) // Is it a cross-reference table? { // Reference: 3.4.3 Cross-Reference Table / Page 93 while (true) { symbol = ScanNextToken(); if (symbol == Symbol.Integer) { int start = _lexer.TokenToInteger; int length = ReadInteger(); for (int id = start; id < start + length; id++) { int position = ReadInteger(); int generation = ReadInteger(); ReadSymbol(Symbol.Keyword); string token = _lexer.Token; // Skip start entry if (id == 0) continue; // Skip unused entries. if (token != "n") continue; // Even it is restricted, an object can exists in more than one subsection. // (PDF Reference Implementation Notes 15). PdfObjectID objectID = new PdfObjectID(id, generation); // Ignore the latter one. if (xrefTable.Contains(objectID)) continue; xrefTable.Add(new PdfReference(objectID, position)); } } else if (symbol == Symbol.Trailer) { ReadSymbol(Symbol.BeginDictionary); PdfTrailer trailer = new PdfTrailer(_document); ReadDictionary(trailer, false); return trailer; } else ParserDiagnostics.HandleUnexpectedToken(_lexer.Token); } } // ReSharper disable once RedundantIfElseBlock because of code readability. else if (symbol == Symbol.Integer) // Is it an cross-reference stream? { // Reference: 3.4.7 Cross-Reference Streams / Page 93 // TODO: Handle PDF files larger than 2 GiB, see implementation note 21 in Appendix H. // The parsed integer is the object id of the cross-refernece stream. return ReadXRefStream(xrefTable); } return null; }
void Initialize() { //_info = new PdfInfo(this); _fontTable = new PdfFontTable(this); _imageTable = new PdfImageTable(this); _trailer = new PdfTrailer(this); _irefTable = new PdfCrossReferenceTable(this); _trailer.CreateNewDocumentIDs(); }
internal PdfDocument(Lexer lexer) { //PdfDocument.Gob.AttatchDocument(Handle); _creation = DateTime.Now; _state = DocumentState.Imported; //_info = new PdfInfo(this); //_pages = new PdfPages(this); //_fontTable = new PdfFontTable(); //_catalog = new PdfCatalog(this); ////_font = new PdfFont(); //_objects = new PdfObjectTable(this); //_trailer = new PdfTrailer(this); _irefTable = new PdfCrossReferenceTable(this); _lexer = lexer; }