/// <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> /// Initializes a new PDFReference instance from the specified object identifier and file position. /// </summary> public PDFReference(PDFObjectID objectID, int position) { _objectID = objectID; Position = position; #if UNIQUE_IREF && DEBUG _uid = ++s_counter; #endif }
/// <summary> /// Opens an existing PDF document. /// </summary> public static PDFDocument Open(Stream stream, string password, PDFDocumentOpenMode openmode, PDFPasswordProvider passwordProvider) { PDFDocument document; try { Lexer lexer = new Lexer(stream); document = new PDFDocument(lexer); document.State |= DocumentState.Imported; document.OpenMode = openmode; document.FileSize = stream.Length; // Get file version. byte[] header = new byte[1024]; stream.Position = 0; stream.Read(header, 0, 1024); document._version = GetPDFFileVersion(header); if (document._version == 0) { throw new InvalidOperationException(PSSR.InvalidPDF); } document.IrefTable.IsUnderConstruction = true; Parser parser = new Parser(document); // Read all trailers or cross-reference streams, but no objects. document.Trailer = parser.ReadTrailer(); if (document.Trailer == null) { ParserDiagnostics.ThrowParserException("Invalid PDF file: no trailer found."); // TODO L10N using PSSR. } Debug.Assert(document.IrefTable.IsUnderConstruction); document.IrefTable.IsUnderConstruction = false; // Is document encrypted? PDFReference xrefEncrypt = document.Trailer.Elements[PDFTrailer.Keys.Encrypt] as PDFReference; if (xrefEncrypt != null) { //xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false); PDFObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false, false); encrypt.Reference = xrefEncrypt; xrefEncrypt.Value = encrypt; PDFStandardSecurityHandler securityHandler = document.SecurityHandler; TryAgain: PasswordValidity validity = securityHandler.ValidatePassword(password); if (validity == PasswordValidity.Invalid) { if (passwordProvider != null) { PDFPasswordProviderArgs args = new PDFPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { if (password == null) { throw new PDFReaderException(PSSR.PasswordRequired); } else { throw new PDFReaderException(PSSR.InvalidPassword); } } } else if (validity == PasswordValidity.UserPassword && openmode == PDFDocumentOpenMode.Modify) { if (passwordProvider != null) { PDFPasswordProviderArgs args = new PDFPasswordProviderArgs(); passwordProvider(args); if (args.Abort) { return(null); } password = args.Password; goto TryAgain; } else { throw new PDFReaderException(PSSR.OwnerPasswordRequired); } } } else { if (password != null) { // Password specified but document is not encrypted. // ignore } } PDFReference[] irefs2 = document.IrefTable.AllReferences; int count2 = irefs2.Length; // 3rd: Create iRefs for all compressed objects. Dictionary <int, object> objectStreams = new Dictionary <int, object>(); for (int idx = 0; idx < count2; idx++) { PDFReference iref = irefs2[idx]; if (iref.Value is PDFCrossReferenceStream xrefStream) { for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++) { PDFCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2]; // Is type xref to compressed object? if (item.Type == 2) { //PDFReference irefNew = parser.ReadCompressedObject(new PDFObjectID((int)item.Field2), (int)item.Field3); //document._irefTable.Add(irefNew); int objectNumber = (int)item.Field2; if (!objectStreams.ContainsKey(objectNumber)) { objectStreams.Add(objectNumber, null); PDFObjectID objectID = new PDFObjectID((int)item.Field2); parser.ReadIRefsFromCompressedObject(objectID); } } } } } // 4th: Read compressed objects. for (int idx = 0; idx < count2; idx++) { PDFReference iref = irefs2[idx]; if (iref.Value is PDFCrossReferenceStream xrefStream) { for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++) { PDFCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2]; // Is type xref to compressed object? if (item.Type == 2) { PDFReference irefNew = parser.ReadCompressedObject(new PDFObjectID((int)item.Field2), (int)item.Field3); Debug.Assert(document.IrefTable.Contains(iref.ObjectID)); //document._irefTable.Add(irefNew); } } } } PDFReference[] irefs = document.IrefTable.AllReferences; int count = irefs.Length; // Read all indirect objects. for (int idx = 0; idx < count; idx++) { PDFReference iref = irefs[idx]; if (iref.Value == null) { #if DEBUG_ if (iref.ObjectNumber == 1074) { iref.GetType(); } #endif try { Debug.Assert(document.IrefTable.Contains(iref.ObjectID)); PDFObject pdfObject = parser.ReadObject(null, iref.ObjectID, false, false); Debug.Assert(pdfObject.Reference == iref); pdfObject.Reference = iref; Debug.Assert(pdfObject.Reference.Value != null, "Something went wrong."); } catch (Exception ex) { Debug.WriteLine(ex.Message); // 4STLA rethrow exception to notify caller. throw; } } else { Debug.Assert(document.IrefTable.Contains(iref.ObjectID)); //iref.GetType(); } // Set maximum object number. document.IrefTable._maxObjectNumber = Math.Max(document.IrefTable._maxObjectNumber, iref.ObjectNumber); } // Encrypt all objects. if (xrefEncrypt != null) { document.SecurityHandler.EncryptDocument(); } // Fix references of trailer values and then objects and irefs are consistent. document.Trailer.Finish(); #if DEBUG_ // Some tests... PDFReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer); reachables.GetType(); reachables = document.xrefTable.AllXRefs; document.xrefTable.CheckConsistence(); #endif if (openmode == PDFDocumentOpenMode.Modify) { // Create new or change existing document IDs. if (document.Internals.SecondDocumentID == "") { document.Trailer.CreateNewDocumentIDs(); } else { byte[] agTemp = Guid.NewGuid().ToByteArray(); document.Internals.SecondDocumentID = PDFEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length); } // Change modification date document.Info.ModificationDate = DateTime.Now; // Remove all unreachable objects int removed = document.IrefTable.Compact(); if (removed != 0) { Debug.WriteLine("Number of deleted unreachable objects: " + removed); } // Force flattening of page tree PDFPages pages = document.Pages; Debug.Assert(pages != null); //bool b = document.irefTable.Contains(new PDFObjectID(1108)); //b.GetType(); document.IrefTable.CheckConsistence(); document.IrefTable.Renumber(); document.IrefTable.CheckConsistence(); } } catch (Exception ex) { Debug.WriteLine(ex.Message); throw; } return(document); }
/// <summary> /// Gets the cloned object that corresponds to the specified external identifier. /// </summary> public PDFReference this[PDFObjectID externalID] => _externalIDs[externalID.ToString()];
/// <summary> /// Adds a cloned object to this table. /// </summary> /// <param name="externalID">The object identifier in the foreign object.</param> /// <param name="iref">The cross reference to the clone of the foreign object, which belongs to /// this document. In general the clone has a different object identifier.</param> public void Add(PDFObjectID externalID, PDFReference iref) => _externalIDs[externalID.ToString()] = iref;
/// <summary> /// Indicates whether the specified object is already imported. /// </summary> public bool Contains(PDFObjectID externalID) => _externalIDs.ContainsKey(externalID.ToString());