#region PDFsharp - A .NET library for processing PDF // // Authors: // Stefan Lange // // Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany) // // http://www.pdfsharp.com // http://sourceforge.net/projects/pdfsharp // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #endregion using System; using System.Diagnostics; using System.Reflection; using System.Text; using System.IO; using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf.Advanced { /// /// Provides access to the internal document data structures. This class prevents the public /// interfaces from pollution with to much internal functions. /// public class PdfInternals // TODO: PdfDocumentInternals... PdfPageInterals etc. { internal PdfInternals(PdfDocument document) { _document = document; } readonly PdfDocument _document; /// /// Gets or sets the first document identifier. /// public string FirstDocumentID { get { return _document._trailer.GetDocumentID(0); } set { _document._trailer.SetDocumentID(0, value); } } /// /// Gets the first document identifier as GUID. /// public Guid FirstDocumentGuid { get { return GuidFromString(_document._trailer.GetDocumentID(0)); } } /// /// Gets or sets the second document identifier. /// public string SecondDocumentID { get { return _document._trailer.GetDocumentID(1); } set { _document._trailer.SetDocumentID(1, value); } } /// /// Gets the first document identifier as GUID. /// public Guid SecondDocumentGuid { get { return GuidFromString(_document._trailer.GetDocumentID(0)); } } Guid GuidFromString(string id) { if (id == null || id.Length != 16) return Guid.Empty; StringBuilder guid = new StringBuilder(); for (int idx = 0; idx < 16; idx++) guid.AppendFormat("{0:X2}", (byte)id[idx]); return new Guid(guid.ToString()); } /// /// Gets the catalog dictionary. /// public PdfCatalog Catalog { get { return _document.Catalog; } } /// /// Gets the ExtGStateTable object. /// public PdfExtGStateTable ExtGStateTable { get { return _document.ExtGStateTable; } } /// /// Returns the object with the specified Identifier, or null, if no such object exists. /// public PdfObject GetObject(PdfObjectID objectID) { return _document._irefTable[objectID].Value; } /// /// Maps the specified external object to the substitute object in this document. /// Returns null if no such object exists. /// public PdfObject MapExternalObject(PdfObject externalObject) { PdfFormXObjectTable table = _document.FormTable; PdfImportedObjectTable iot = table.GetImportedObjectTable(externalObject.Owner); PdfReference reference = iot[externalObject.ObjectID]; return reference == null ? null : reference.Value; } /// /// Returns the PdfReference of the specified object, or null, if the object is not in the /// document's object table. /// public static PdfReference GetReference(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); return obj.Reference; } /// /// Gets the object identifier of the specified object. /// public static PdfObjectID GetObjectID(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); return obj.ObjectID; } /// /// Gets the object number of the specified object. /// public static int GetObjectNumber(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); return obj.ObjectNumber; } /// /// Gets the generation number of the specified object. /// public static int GenerationNumber(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); return obj.GenerationNumber; } /// /// Gets all indirect objects ordered by their object identifier. /// public PdfObject[] GetAllObjects() { PdfReference[] irefs = _document._irefTable.AllReferences; int count = irefs.Length; PdfObject[] objects = new PdfObject[count]; for (int idx = 0; idx < count; idx++) objects[idx] = irefs[idx].Value; return objects; } /// /// Gets all indirect objects ordered by their object identifier. /// [Obsolete("Use GetAllObjects.")] // Properties should not return arrays public PdfObject[] AllObjects { get { return GetAllObjects(); } } /// /// Creates the indirect object of the specified type, adds it to the document, /// and returns the object. /// public T CreateIndirectObject() where T : PdfObject { #if true T obj = Activator.CreateInstance(); _document._irefTable.Add(obj); #else T result = null; #if !NETFX_CORE && !UWP ConstructorInfo ctorInfo = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.ExactBinding, null, new Type[] { typeof(PdfDocument) }, null); #else ConstructorInfo ctorInfo = null; // TODO #endif if (ctorInfo != null) { result = (T)ctorInfo.Invoke(new object[] { _document }); Debug.Assert(result != null); AddObject(result); } Debug.Assert(result != null, "CreateIndirectObject failed with type " + typeof(T).FullName); #endif return obj; } /// /// Adds an object to the PDF document. This operation and only this operation makes the object /// an indirect object owned by this document. /// public void AddObject(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); if (obj.Owner == null) obj.Document = _document; else if (obj.Owner != _document) throw new InvalidOperationException("Object does not belong to this document."); _document._irefTable.Add(obj); } /// /// Removes an object from the PDF document. /// public void RemoveObject(PdfObject obj) { if (obj == null) throw new ArgumentNullException("obj"); if (obj.Reference == null) throw new InvalidOperationException("Only indirect objects can be removed."); if (obj.Owner != _document) throw new InvalidOperationException("Object does not belong to this document."); _document._irefTable.Remove(obj.Reference); } /// /// Returns an array containing the specified object as first element follows by its transitive /// closure. The closure of an object are all objects that can be reached by indirect references. /// The transitive closure is the result of applying the calculation of the closure to a closure /// as long as no new objects came along. This is e.g. useful for getting all objects belonging /// to the resources of a page. /// public PdfObject[] GetClosure(PdfObject obj) { return GetClosure(obj, Int32.MaxValue); } /// /// Returns an array containing the specified object as first element follows by its transitive /// closure limited by the specified number of iterations. /// public PdfObject[] GetClosure(PdfObject obj, int depth) { PdfReference[] references = _document._irefTable.TransitiveClosure(obj, depth); int count = references.Length + 1; PdfObject[] objects = new PdfObject[count]; objects[0] = obj; for (int idx = 1; idx < count; idx++) objects[idx] = references[idx - 1].Value; return objects; } /// /// Writes a PdfItem into the specified stream. /// // This function exists to keep PdfWriter and PdfItem.WriteObject internal. public void WriteObject(Stream stream, PdfItem item) { // Never write an encrypted object PdfWriter writer = new PdfWriter(stream, null); writer.Options = PdfWriterOptions.OmitStream; item.WriteObject(writer); } /// /// The name of the custom value key. /// public string CustomValueKey = "/PdfSharp.CustomValue"; } }