#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.Collections.Generic; using System.Diagnostics; using System.Collections; using System.Globalization; using System.Text; using PdfSharp.Pdf.Advanced; using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf { /// /// Represents a PDF array object. /// [DebuggerDisplay("{DebuggerDisplay}")] public class PdfArray : PdfObject, IEnumerable { /// /// Initializes a new instance of the class. /// public PdfArray() { } /// /// Initializes a new instance of the class. /// /// The document. public PdfArray(PdfDocument document) : base(document) { } /// /// Initializes a new instance of the class. /// /// The document. /// The items. public PdfArray(PdfDocument document, params PdfItem[] items) : base(document) { foreach (PdfItem item in items) Elements.Add(item); } /// /// Initializes a new instance from an existing dictionary. Used for object type transformation. /// /// The array. protected PdfArray(PdfArray array) : base(array) { if (array._elements != null) array._elements.ChangeOwner(this); } /// /// Creates a copy of this array. Direct elements are deep copied. /// Indirect references are not modified. /// public new PdfArray Clone() { return (PdfArray)Copy(); } /// /// Implements the copy mechanism. /// protected override object Copy() { PdfArray array = (PdfArray)base.Copy(); if (array._elements != null) { array._elements = array._elements.Clone(); int count = array._elements.Count; for (int idx = 0; idx < count; idx++) { PdfItem item = array._elements[idx]; if (item is PdfObject) array._elements[idx] = item.Clone(); } } return array; } /// /// Gets the collection containing the elements of this object. /// public ArrayElements Elements { get { return _elements ?? (_elements = new ArrayElements(this)); } } /// /// Returns an enumerator that iterates through a collection. /// public virtual IEnumerator GetEnumerator() { return Elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Returns a string with the content of this object in a readable form. Useful for debugging purposes only. /// public override string ToString() { StringBuilder pdf = new StringBuilder(); pdf.Append("[ "); int count = Elements.Count; for (int idx = 0; idx < count; idx++) pdf.Append(Elements[idx] + " "); pdf.Append("]"); return pdf.ToString(); } internal override void WriteObject(PdfWriter writer) { writer.WriteBeginObject(this); int count = Elements.Count; for (int idx = 0; idx < count; idx++) { PdfItem value = Elements[idx]; value.WriteObject(writer); } writer.WriteEndObject(); } /// /// Represents the elements of an PdfArray. /// public sealed class ArrayElements : IList, ICloneable { internal ArrayElements(PdfArray array) { _elements = new List(); _ownerArray = array; } object ICloneable.Clone() { ArrayElements elements = (ArrayElements)MemberwiseClone(); elements._elements = new List(elements._elements); elements._ownerArray = null; return elements; } /// /// Creates a shallow copy of this object. /// public ArrayElements Clone() { return (ArrayElements)((ICloneable)this).Clone(); } /// /// Moves this instance to another array during object type transformation. /// internal void ChangeOwner(PdfArray array) { if (_ownerArray != null) { // ??? } // Set new owner. _ownerArray = array; // Set owners elements to this. array._elements = this; } /// /// Converts the specified value to boolean. /// If the value does not exist, the function returns false. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public bool GetBoolean(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return false; PdfBoolean boolean = obj as PdfBoolean; if (boolean != null) return boolean.Value; PdfBooleanObject booleanObject = obj as PdfBooleanObject; if (booleanObject != null) return booleanObject.Value; throw new InvalidCastException("GetBoolean: Object is not a boolean."); } /// /// Converts the specified value to integer. /// If the value does not exist, the function returns 0. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public int GetInteger(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return 0; PdfInteger integer = obj as PdfInteger; if (integer != null) return integer.Value; PdfIntegerObject integerObject = obj as PdfIntegerObject; if (integerObject != null) return integerObject.Value; throw new InvalidCastException("GetInteger: Object is not an integer."); } /// /// Converts the specified value to double. /// If the value does not exist, the function returns 0. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public double GetReal(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return 0; PdfReal real = obj as PdfReal; if (real != null) return real.Value; PdfRealObject realObject = obj as PdfRealObject; if (realObject != null) return realObject.Value; PdfInteger integer = obj as PdfInteger; if (integer != null) return integer.Value; PdfIntegerObject integerObject = obj as PdfIntegerObject; if (integerObject != null) return integerObject.Value; throw new InvalidCastException("GetReal: Object is not a number."); } /// /// Converts the specified value to double?. /// If the value does not exist, the function returns null. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public double? GetNullableReal(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return null; PdfNull @null = obj as PdfNull; if (@null != null) return null; PdfNullObject nullObject = obj as PdfNullObject; if (nullObject != null) return null; PdfReal real = obj as PdfReal; if (real != null) return real.Value; PdfRealObject realObject = obj as PdfRealObject; if (realObject != null) return realObject.Value; PdfInteger integer = obj as PdfInteger; if (integer != null) return integer.Value; PdfIntegerObject integerObject = obj as PdfIntegerObject; if (integerObject != null) return integerObject.Value; throw new InvalidCastException("GetReal: Object is not a number."); } /// /// Converts the specified value to string. /// If the value does not exist, the function returns the empty string. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public string GetString(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return String.Empty; PdfString str = obj as PdfString; if (str != null) return str.Value; PdfStringObject strObject = obj as PdfStringObject; if (strObject != null) return strObject.Value; throw new InvalidCastException("GetString: Object is not a string."); } /// /// Converts the specified value to a name. /// If the value does not exist, the function returns the empty string. /// If the value is not convertible, the function throws an InvalidCastException. /// If the index is out of range, the function throws an ArgumentOutOfRangeException. /// public string GetName(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); object obj = this[index]; if (obj == null) return String.Empty; PdfName name = obj as PdfName; if (name != null) return name.Value; PdfNameObject nameObject = obj as PdfNameObject; if (nameObject != null) return nameObject.Value; throw new InvalidCastException("GetName: Object is not a name."); } /// /// Returns the indirect object if the value at the specified index is a PdfReference. /// [Obsolete("Use GetObject, GetDictionary, GetArray, or GetReference")] public PdfObject GetIndirectObject(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); PdfReference reference = this[index] as PdfReference; if (reference != null) return reference.Value; return null; } /// /// Gets the PdfObject with the specified index, or null, if no such object exists. If the index refers to /// a reference, the referenced PdfObject is returned. /// public PdfObject GetObject(int index) { if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange); PdfItem item = this[index]; PdfReference reference = item as PdfReference; if (reference != null) return reference.Value; return item as PdfObject; } /// /// Gets the PdfArray with the specified index, or null, if no such object exists. If the index refers to /// a reference, the referenced PdfArray is returned. /// public PdfDictionary GetDictionary(int index) { return GetObject(index) as PdfDictionary; } /// /// Gets the PdfArray with the specified index, or null, if no such object exists. If the index refers to /// a reference, the referenced PdfArray is returned. /// public PdfArray GetArray(int index) { return GetObject(index) as PdfArray; } /// /// Gets the PdfReference with the specified index, or null, if no such object exists. /// public PdfReference GetReference(int index) { PdfItem item = this[index]; return item as PdfReference; } /// /// Gets all items of this array. /// public PdfItem[] Items { get { return _elements.ToArray(); } } #region IList Members /// /// Returns false. /// public bool IsReadOnly { get { return false; } } /// /// Gets or sets an item at the specified index. /// /// public PdfItem this[int index] { get { return _elements[index]; } set { if (value == null) throw new ArgumentNullException("value"); _elements[index] = value; } } /// /// Removes the item at the specified index. /// public void RemoveAt(int index) { _elements.RemoveAt(index); } /// /// Removes the first occurrence of a specific object from the array/>. /// public bool Remove(PdfItem item) { return _elements.Remove(item); } /// /// Inserts the item the specified index. /// public void Insert(int index, PdfItem value) { _elements.Insert(index, value); } /// /// Determines whether the specified value is in the array. /// public bool Contains(PdfItem value) { return _elements.Contains(value); } /// /// Removes all items from the array. /// public void Clear() { _elements.Clear(); } /// /// Gets the index of the specified item. /// public int IndexOf(PdfItem value) { return _elements.IndexOf(value); } /// /// Appends the specified object to the array. /// public void Add(PdfItem value) { // TODO: ??? //Debug.Assert((value is PdfObject && ((PdfObject)value).Reference == null) | !(value is PdfObject), // "You try to set an indirect object directly into an array."); PdfObject obj = value as PdfObject; if (obj != null && obj.IsIndirect) _elements.Add(obj.Reference); else _elements.Add(value); } /// /// Returns false. /// public bool IsFixedSize { get { return false; } } #endregion #region ICollection Members /// /// Returns false. /// public bool IsSynchronized { get { return false; } } /// /// Gets the number of elements in the array. /// public int Count { get { return _elements.Count; } } /// /// Copies the elements of the array to the specified array. /// public void CopyTo(PdfItem[] array, int index) { _elements.CopyTo(array, index); } /// /// The current implementation return null. /// public object SyncRoot { get { return null; } } #endregion /// /// Returns an enumerator that iterates through the array. /// public IEnumerator GetEnumerator() { return _elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _elements.GetEnumerator(); } /// /// The elements of the array. /// List _elements; /// /// The array this objects belongs to. /// PdfArray _ownerArray; } ArrayElements _elements; /// /// Gets the DebuggerDisplayAttribute text. /// // ReSharper disable UnusedMember.Local string DebuggerDisplay // ReSharper restore UnusedMember.Local { get { #if true return String.Format(CultureInfo.InvariantCulture, "array({0},[{1}])", ObjectID.DebuggerDisplay, _elements == null ? 0 : _elements.Count); #else return String.Format(CultureInfo.InvariantCulture, "array({0},[{1}])", ObjectID.DebuggerDisplay, _elements == null ? 0 : _elements.Count); #endif } } } }