/// <summary> /// Gets a cross reference entry from an object identifier. /// Returns null if no object with the specified ID exists in the object table. /// </summary> public PdfReference this[PdfObjectID objectID] { get { PdfReference iref; ObjectTable.TryGetValue(objectID, out iref); return(iref); } }
/// <summary> /// Indicates whether this instance and a specified object are equal. /// </summary> public override bool Equals(object obj) { if (obj is PdfObjectID) { PdfObjectID id = (PdfObjectID)obj; if (_objectNumber == id._objectNumber) return _generationNumber == id._generationNumber; } return false; }
/// <summary> /// Compares the current object id with another object. /// </summary> public int CompareTo(object obj) { if (obj is PdfObjectID) { PdfObjectID id = (PdfObjectID)obj; if (_objectNumber == id._objectNumber) return _generationNumber - id._generationNumber; return _objectNumber - id._objectNumber; } return 1; }
/// <summary> /// Indicates whether this instance and a specified object are equal. /// </summary> public override bool Equals(object obj) { if (obj is PdfObjectID) { PdfObjectID id = (PdfObjectID)obj; if (_objectNumber == id._objectNumber) { return(_generationNumber == id._generationNumber); } } return(false); }
/// <summary> /// Compares the current object id with another object. /// </summary> public int CompareTo(object obj) { if (obj is PdfObjectID) { PdfObjectID id = (PdfObjectID)obj; if (this.objectNumber == id.objectNumber) { return(this.generationNumber - id.generationNumber); } return(this.objectNumber - id.objectNumber); } return(1); }
/// <summary> /// Sets the object and generation number /// Setting the object identifier makes this object an indirect object, i.e. the object gets /// a PdfReference entry in the PdfReferenceTable. /// </summary> internal void SetObjectID(int objectNumber, int generationNumber) { PdfObjectID objectID = new PdfObjectID(objectNumber, generationNumber); // TODO: check imported if (iref == null) { iref = document.irefTable[objectID]; } if (iref == null) { iref = new PdfReference(this); iref.ObjectID = objectID; } iref.Value = this; iref.Document = document; }
/// <summary> /// Finds a page by its id. Transforms it to PdfPage if necessary. /// </summary> internal PdfPage FindPage(PdfObjectID id) // TODO: public? { PdfPage page = null; foreach (PdfItem item in PagesArray) { PdfReference reference = item as PdfReference; if (reference != null) { PdfDictionary dictionary = reference.Value as PdfDictionary; if (dictionary != null && dictionary.ObjectID == id) { page = dictionary as PdfPage ?? new PdfPage(dictionary); break; } } } return(page); }
/// <summary> /// Sets the object and generation number. /// Setting the object identifier makes this object an indirect object, i.e. the object gets /// a PdfReference entry in the PdfReferenceTable. /// </summary> internal void SetObjectID(int objectNumber, int generationNumber) { PdfObjectID objectID = new PdfObjectID(objectNumber, generationNumber); // TODO: check imported if (_iref == null) { _iref = _document._irefTable[objectID]; } if (_iref == null) { // ReSharper disable once ObjectCreationAsStatement because the new object is set to this object // in the constructor of PdfReference. new PdfReference(this); Debug.Assert(_iref != null); _iref.ObjectID = objectID; } _iref.Value = this; _iref.Document = _document; }
/// <summary> /// Indicates whether the specified object identifier is in the table. /// </summary> public bool Contains(PdfObjectID objectID) { return this.objectTable.ContainsKey(objectID); }
/// <summary> /// Sets the object and generation number. /// Setting the object identifier makes this object an indirect object, i.e. the object gets /// a PdfReference entry in the PdfReferenceTable. /// </summary> internal void SetObjectID(int objectNumber, int generationNumber) { PdfObjectID objectID = new PdfObjectID(objectNumber, generationNumber); // TODO: check imported if (_iref == null) _iref = _document._irefTable[objectID]; if (_iref == null) { // ReSharper disable once ObjectCreationAsStatement because the new object is set to this object // in the constructor of PdfReference. new PdfReference(this); Debug.Assert(_iref != null); _iref.ObjectID = objectID; } _iref.Value = this; _iref.Document = _document; }
/// <summary> /// Returns the object with the specified Identifier, or null, if no such object exists. /// </summary> public PdfObject GetObject(PdfObjectID objectID) { return document.irefTable[objectID].Value; }
/// <summary> /// Gets a cross reference entry from an object identifier. /// Returns null if no object with the specified ID exists in the object table. /// </summary> public PdfReference this[PdfObjectID objectID] { get { PdfReference iref; this.objectTable.TryGetValue(objectID, out iref); return iref; } }
/// <summary> /// /// </summary> PdfTrailer ReadXRefTableAndTrailer(PdfReferenceTable xrefTable) { Debug.Assert(xrefTable != null); Symbol symbol = ScanNextToken(); // Is it an xref stream? if (symbol == Symbol.Integer) throw new PdfReaderException(PSSR.CannotHandleXRefStreams); // TODO: We have all code to handle them -> just do it Debug.Assert(symbol == Symbol.XRef); while (true) { symbol = ScanNextToken(); if (symbol == Symbol.Integer) { int start = this.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(this.document); this.ReadDictionary(trailer, false); return trailer; } else throw new PdfReaderException(PSSR.UnexpectedToken(this.lexer.Token)); } }
/// <summary> /// Sets PDF input stream position the the specified object. /// </summary> public int MoveToObject(PdfObjectID objectID) { int position = this.document.irefTable[objectID].Position; return this.lexer.Position = position; }
/// <summary> /// Parses whatever comes until the specified stop symbol is reached. /// </summary> void ParseObject(Symbol stop) { #if DEBUG_ ParseObjectCounter++; Debug.WriteLine(ParseObjectCounter.ToString()); if (ParseObjectCounter == 178) GetType(); #endif Symbol symbol; while ((symbol = ScanNextToken()) != Symbol.Eof) { if (symbol == stop) return; switch (symbol) { case Symbol.Comment: // ignore comments break; case Symbol.Null: this.stack.Shift(PdfNull.Value); break; case Symbol.Boolean: this.stack.Shift(new PdfBoolean(this.lexer.TokenToBoolean)); break; case Symbol.Integer: this.stack.Shift(new PdfInteger(this.lexer.TokenToInteger)); break; case Symbol.UInteger: this.stack.Shift(new PdfUInteger(this.lexer.TokenToUInteger)); break; case Symbol.Real: this.stack.Shift(new PdfReal(this.lexer.TokenToReal)); break; case Symbol.String: //this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.PDFDocEncoding)); this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.RawEncoding)); break; case Symbol.UnicodeString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.Unicode)); break; case Symbol.HexString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.HexLiteral)); break; case Symbol.UnicodeHexString: this.stack.Shift(new PdfString(this.lexer.Token, PdfStringFlags.Unicode | PdfStringFlags.HexLiteral)); break; case Symbol.Name: this.stack.Shift(new PdfName(this.lexer.Token)); break; case Symbol.R: { Debug.Assert(this.stack.GetItem(-1) is PdfInteger && this.stack.GetItem(-2) is PdfInteger); PdfObjectID objectID = new PdfObjectID(this.stack.GetInteger(-2), this.stack.GetInteger(-1)); PdfReference iref = this.document.irefTable[objectID]; if (iref == null) { // If a document has more than one PdfXRefTable it is possible that the first trailer has // indirect references to objects whos iref entry is not yet read in. if (this.document.irefTable.IsUnderConstruction) { // XRefTable not complete when trailer is read. Create temporary irefs that are // removed later in PdfTrailer.FixXRefs. iref = new PdfReference(objectID, 0); this.stack.Reduce(iref, 2); break; } // PDF Reference section 3.2.9: // An indirect reference to an undefined object is not an error; // it is simply treated as a reference to the null object. this.stack.Reduce(PdfNull.Value, 2); // Let's see what null objects are good for... //Debug.Assert(false, "Null object detected!"); //this.stack.Reduce(PdfNull.Value, 2); } else this.stack.Reduce(iref, 2); break; } case Symbol.BeginArray: PdfArray array = new PdfArray(this.document); ReadArray(array, false); this.stack.Shift(array); break; case Symbol.BeginDictionary: PdfDictionary dict = new PdfDictionary(this.document); ReadDictionary(dict, false); this.stack.Shift(dict); break; case Symbol.BeginStream: throw new NotImplementedException(); default: string error = this.lexer.Token; Debug.Assert(false, "Unexpected: " + error); break; } } throw new PdfReaderException("Unexpected end of file."); }
// /// <summary> // /// Reads a real value directly or (optionally) indirectly from the PDF data stream. // /// </summary> // double ReadReal(bool canBeIndirect) // { // Symbol symbol = this.lexer.ScanNextToken(canBeIndirect); // if (symbol == Symbol.Real || symbol == Symbol.Integer) // return this.lexer.TokenToReal; // else if (symbol == Symbol.R) // { // int position = this.lexer.Position; //// MoveToObject(this.lexer.Token); // ReadObjectID(null); // double f = ReadReal(); // ReadSymbol(Symbol.EndObj); // this.lexer.Position = position; // return f; // } // throw new PdfReaderException(PSSR.UnexpectedToken(this.lexer.Token)); // } // // double ReadReal() // { // return ReadReal(false); // } // /// <summary> // /// Reads an object from the PDF input stream. If the object has a specialized parser, it it used. // /// </summary> // public static PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID) // { // if (pdfObject == null) // throw new ArgumentNullException("pdfObject"); // if (pdfObject.Document == null) // throw new ArgumentException(PSSR.OwningDocumentRequired, "pdfObject"); // // Type type = pdfObject.GetType(); // PdfParser parser = CreateParser(pdfObject.Document, type); // return parser.ReadObject(pdfObject, objectID, false); // } /// <summary> /// Reads an object from the PDF input stream using the default parser. /// </summary> public static PdfObject ReadObject(PdfDocument owner, PdfObjectID objectID) { if (owner == null) throw new ArgumentNullException("owner"); Parser parser = new Parser(owner); return parser.ReadObject(null, objectID, false); }
/// <summary> /// Reads PDF object from input stream. /// </summary> /// <param name="pdfObject">Either the instance of a derived type or null. If it is null /// an appropriate object is created.</param> /// <param name="objectID">The address of the object.</param> /// <param name="includeReferences">If true, specifies that all indirect objects /// are included recursively.</param> public PdfObject ReadObject(PdfObject pdfObject, PdfObjectID objectID, bool includeReferences) { MoveToObject(objectID); int objectNumber = ReadInteger(); int generationNumber = ReadInteger(); #if DEBUG // The following assertion sometime failed (see below) //Debug.Assert(objectID == new PdfObjectID(objectNumber, generationNumber)); if (objectID != new PdfObjectID(objectNumber, generationNumber)) { // A special kind of bug? Or is this an undocumented PDF feature? // PDF4NET 2.6 provides a sample called 'Unicode', which produces a file 'unicode.pdf' // The iref table of this file contains the following entries: // iref // 0 148 // 0000000000 65535 f // 0000000015 00000 n // 0000000346 00000 n // .... // 0000083236 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000083045 00000 n // 0000080334 00000 n // .... // Object 84, 85, 86, and 87 maps to the same dictionary, but all PDF readers I tested // ignores this mismatch! The following assertion failed about 50 times with this file. #if true_ string message = String.Format("xref entry {0} {1} maps to object {2} {3}.", objectID.ObjectNumber, objectID.GenerationNumber, objectNumber, generationNumber); Debug.Assert(false, message); #endif } #endif // Always use object ID from iref table (see above) objectNumber = objectID.ObjectNumber; generationNumber = objectID.GenerationNumber; #if true_ Debug.WriteLine(String.Format("obj: {0} {1}", objectNumber, generationNumber)); #endif ReadSymbol(Symbol.Obj); bool checkForStream = false; Symbol symbol = ScanNextToken(); switch (symbol) { case Symbol.BeginArray: PdfArray array; if (pdfObject == null) array = new PdfArray(this.document); else array = (PdfArray)pdfObject; //PdfObject.RegisterObject(array, objectID, generation); pdfObject = ReadArray(array, includeReferences); pdfObject.SetObjectID(objectNumber, generationNumber); break; case Symbol.BeginDictionary: PdfDictionary dict; if (pdfObject == null) dict = new PdfDictionary(this.document); else dict = (PdfDictionary)pdfObject; //PdfObject.RegisterObject(dict, objectID, generation); checkForStream = true; pdfObject = ReadDictionary(dict, includeReferences); pdfObject.SetObjectID(objectNumber, generationNumber); break; // Acrobat 6 Professional proudly presents: The Null object! // Even with a one-digit object number an indirect reference «x 0 R» to this object is // one character larger than the direct use of «null». Probable this is the reason why // it is true that Acrobat Web Capture 6.0 creates this object, but obviously never // creates a reference to it! case Symbol.Null: pdfObject = new PdfNullObject(this.document); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Boolean: pdfObject = new PdfBooleanObject(this.document, this.lexer.Token == Boolean.TrueString); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Integer: pdfObject = new PdfIntegerObject(this.document, this.lexer.TokenToInteger); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.UInteger: pdfObject = new PdfUIntegerObject(this.document, this.lexer.TokenToUInteger); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Real: pdfObject = new PdfRealObject(this.document, this.lexer.TokenToReal); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.String: pdfObject = new PdfStringObject(this.document, this.lexer.Token); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Name: pdfObject = new PdfNameObject(this.document, this.lexer.Token); pdfObject.SetObjectID(objectNumber, generationNumber); ReadSymbol(Symbol.EndObj); return pdfObject; case Symbol.Keyword: // Should not come here anymore throw new NotImplementedException("Keyword"); default: // Should not come here anymore throw new NotImplementedException("unknown token"); } symbol = ScanNextToken(); if (symbol == Symbol.BeginStream) { PdfDictionary dict = (PdfDictionary)pdfObject; Debug.Assert(checkForStream, "Unexpected stream..."); int length = GetStreamLength(dict); byte[] bytes = this.lexer.ReadStream(length); #if true_ if (dict.Elements.GetString("/Filter") == "/FlateDecode") { if (dict.Elements["/Subtype"] == null) { try { byte[] decoded = Filtering.FlateDecode.Decode(bytes); if (decoded.Length == 0) goto End; string pageContent = Filtering.FlateDecode.DecodeToString(bytes); if (pageContent.Length > 100) pageContent = pageContent.Substring(pageContent.Length - 100); pageContent.GetType(); bytes = decoded; dict.Elements.Remove("/Filter"); dict.Elements.SetInteger("/Length", bytes.Length); } catch { } } End:; } #endif PdfDictionary.PdfStream stream = new PdfDictionary.PdfStream(bytes, dict); dict.Stream = stream; ReadSymbol(Symbol.EndStream); symbol = ScanNextToken(); } if (symbol != Symbol.EndObj) throw new PdfReaderException(PSSR.UnexpectedToken(this.lexer.Token)); return pdfObject; }
/// <summary> /// Indicates whether the specified object identifier is in the table. /// </summary> public bool Contains(PdfObjectID objectID) { return(ObjectTable.ContainsKey(objectID)); }
/// <summary> /// Gets a cross reference entry from an object identifier. /// </summary> public PdfReference this[PdfObjectID objectID] { get { return (PdfReference)this.objectTable[objectID]; } }
/// <summary> /// Set the hash key for the specified object. /// </summary> internal void SetHashKey(PdfObjectID id) { #if !SILVERLIGHT byte[] objectId = new byte[5]; this.md5.Initialize(); // Split the object number and generation objectId[0] = (byte)id.ObjectNumber; objectId[1] = (byte)(id.ObjectNumber >> 8); objectId[2] = (byte)(id.ObjectNumber >> 16); objectId[3] = (byte)id.GenerationNumber; objectId[4] = (byte)(id.GenerationNumber >> 8); this.md5.TransformBlock(this.encryptionKey, 0, this.encryptionKey.Length, this.encryptionKey, 0); this.md5.TransformFinalBlock(objectId, 0, objectId.Length); this.key = this.md5.Hash; this.md5.Initialize(); this.keySize = this.encryptionKey.Length + 5; if (this.keySize > 16) this.keySize = 16; #endif }
/// <summary> /// Sets the object and generation number /// Setting the object identifier makes this object an indirect object, i.e. the object gets /// a PdfReference entry in the PdfReferenceTable. /// </summary> internal void SetObjectID(int objectNumber, int generationNumber) { PdfObjectID objectID = new PdfObjectID(objectNumber, generationNumber); // TODO: check imported if (this.iref == null) this.iref = this.document.irefTable[objectID]; if (this.iref == null) { this.iref = new PdfReference(this); this.iref.ObjectID = objectID; } this.iref.Value = this; this.iref.Document = this.document; }