git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.Pdf / PdfArray.cs
1 #region PDFsharp - A .NET library for processing PDF\r
2 //\r
3 // Authors:\r
4 //   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)\r
5 //\r
6 // Copyright (c) 2005-2009 empira Software GmbH, Cologne (Germany)\r
7 //\r
8 // http://www.pdfsharp.com\r
9 // http://sourceforge.net/projects/pdfsharp\r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining a\r
12 // copy of this software and associated documentation files (the "Software"),\r
13 // to deal in the Software without restriction, including without limitation\r
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15 // and/or sell copies of the Software, and to permit persons to whom the\r
16 // Software is furnished to do so, subject to the following conditions:\r
17 //\r
18 // The above copyright notice and this permission notice shall be included\r
19 // in all copies or substantial portions of the Software.\r
20 //\r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \r
27 // DEALINGS IN THE SOFTWARE.\r
28 #endregion\r
29 \r
30 using System;\r
31 using System.Collections.Generic;\r
32 using System.Diagnostics;\r
33 using System.Collections;\r
34 using System.Text;\r
35 using System.IO;\r
36 using PdfSharp.Internal;\r
37 using PdfSharp.Pdf.Advanced;\r
38 using PdfSharp.Pdf.IO;\r
39 \r
40 namespace PdfSharp.Pdf\r
41 {\r
42   /// <summary>\r
43   /// Represents a PDF array object.\r
44   /// </summary>\r
45   [DebuggerDisplay("(elements={Elements.Count})")]\r
46   public class PdfArray : PdfObject, IEnumerable<PdfItem>\r
47   {\r
48     ArrayElements elements;\r
49 \r
50     /// <summary>\r
51     /// Initializes a new instance of the <see cref="PdfArray"/> class.\r
52     /// </summary>\r
53     public PdfArray()\r
54     {\r
55     }\r
56 \r
57     /// <summary>\r
58     /// Initializes a new instance of the <see cref="PdfArray"/> class.\r
59     /// </summary>\r
60     /// <param name="document">The document.</param>\r
61     public PdfArray(PdfDocument document)\r
62       : base(document)\r
63     {\r
64     }\r
65 \r
66     /// <summary>\r
67     /// Initializes a new instance of the <see cref="PdfArray"/> class.\r
68     /// </summary>\r
69     /// <param name="document">The document.</param>\r
70     /// <param name="items">The items.</param>\r
71     public PdfArray(PdfDocument document, params PdfItem[] items)\r
72       : base(document)\r
73     {\r
74       foreach (PdfItem item in items)\r
75         Elements.Add(item);\r
76     }\r
77 \r
78     /// <summary>\r
79     /// Initializes a new instance from an existing dictionary. Used for object type transformation.\r
80     /// </summary>\r
81     /// <param name="array">The array.</param>\r
82     protected PdfArray(PdfArray array)\r
83       : base(array)\r
84     {\r
85       if (array.elements != null)\r
86         array.elements.SetOwner(this);\r
87     }\r
88 \r
89     /// <summary>\r
90     /// Creates a copy of this array. Direct elements are deep copied. Indirect references are not\r
91     /// modified.\r
92     /// </summary>\r
93     public new PdfArray Clone()\r
94     {\r
95       return (PdfArray)Copy();\r
96     }\r
97 \r
98     /// <summary>\r
99     /// Implements the copy mechanism.\r
100     /// </summary>\r
101     protected override object Copy()\r
102     {\r
103       PdfArray array = (PdfArray)base.Copy();\r
104       if (array.elements != null)\r
105       {\r
106         array.elements = array.elements.Clone();\r
107         int count = array.elements.Count;\r
108         for (int idx = 0; idx < count; idx++)\r
109         {\r
110           PdfItem item = array.elements[idx];\r
111           if (item is PdfObject)\r
112             array.elements[idx] = item.Clone();\r
113         }\r
114       }\r
115       return array;\r
116     }\r
117 \r
118     /// <summary>\r
119     /// Gets the collection containing the elements of this object.\r
120     /// </summary>\r
121     public ArrayElements Elements\r
122     {\r
123       get\r
124       {\r
125         if (this.elements == null)\r
126           this.elements = new ArrayElements(this);\r
127         return this.elements;\r
128       }\r
129     }\r
130 \r
131     /// <summary>\r
132     /// Returns an enumerator that iterates through a collection.\r
133     /// </summary>\r
134     public virtual IEnumerator<PdfItem> GetEnumerator()\r
135     {\r
136       return Elements.GetEnumerator();\r
137     }\r
138 \r
139     IEnumerator IEnumerable.GetEnumerator()\r
140     {\r
141       return GetEnumerator();\r
142     }\r
143 \r
144     /// <summary>\r
145     /// Returns a string with the content of this object in a readable form. Useful for debugging purposes only.\r
146     /// </summary>\r
147     public override string ToString()\r
148     {\r
149       StringBuilder pdf = new StringBuilder();\r
150       pdf.Append("[ ");\r
151       int count = Elements.Count;\r
152       for (int idx = 0; idx < count; idx++)\r
153         pdf.Append(Elements[idx].ToString() + " ");\r
154       pdf.Append("]");\r
155       return pdf.ToString();\r
156     }\r
157 \r
158     internal override void WriteObject(PdfWriter writer)\r
159     {\r
160       writer.WriteBeginObject(this);\r
161       int count = Elements.Count;\r
162       for (int idx = 0; idx < count; idx++)\r
163       {\r
164         PdfItem value = Elements[idx];\r
165         value.WriteObject(writer);\r
166       }\r
167       writer.WriteEndObject();\r
168     }\r
169 \r
170     /// <summary>\r
171     /// Represents the elements of an PdfArray.\r
172     /// </summary>\r
173     public sealed class ArrayElements : IList<PdfItem>, ICloneable\r
174     {\r
175       List<PdfItem> elements;\r
176       PdfArray owner;\r
177 \r
178       internal ArrayElements(PdfArray array)\r
179       {\r
180         this.elements = new List<PdfItem>();\r
181         this.owner = array;\r
182       }\r
183 \r
184       object ICloneable.Clone()\r
185       {\r
186         ArrayElements elements = (ArrayElements)MemberwiseClone();\r
187         elements.elements = new List<PdfItem>(elements.elements);\r
188         elements.owner = null;\r
189         return elements;\r
190       }\r
191 \r
192       /// <summary>\r
193       /// Creates a shallow copy of this object.\r
194       /// </summary>\r
195       public ArrayElements Clone()\r
196       {\r
197         return (ArrayElements)((ICloneable)this).Clone();\r
198       }\r
199 \r
200       /// <summary>\r
201       /// Moves this instance to another dictionary during object type transformation.\r
202       /// </summary>\r
203       internal void SetOwner(PdfArray array)\r
204       {\r
205         this.owner = array;\r
206         array.elements = this;\r
207       }\r
208 \r
209       /// <summary>\r
210       /// Converts the specified value to boolean.\r
211       /// If the value not exists, the function returns false.\r
212       /// If the value is not convertible, the function throws an InvalidCastException.\r
213       /// If the index is out of range, the function throws an ArgumentOutOfRangeException.\r
214       /// </summary>\r
215       public bool GetBoolean(int index)\r
216       {\r
217         if (index < 0 || index >= Count)\r
218           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
219 \r
220         object obj = this[index];\r
221         if (obj == null)\r
222           return false;\r
223         if (obj is PdfBoolean)\r
224           return ((PdfBoolean)obj).Value;\r
225         else if (obj is PdfBooleanObject)\r
226           return ((PdfBooleanObject)obj).Value;\r
227         throw new InvalidCastException("GetBoolean: Object is not a boolean.");\r
228       }\r
229 \r
230       /// <summary>\r
231       /// Converts the specified value to integer.\r
232       /// If the value not exists, the function returns 0.\r
233       /// If the value is not convertible, the function throws an InvalidCastException.\r
234       /// If the index is out of range, the function throws an ArgumentOutOfRangeException.\r
235       /// </summary>\r
236       public int GetInteger(int index)\r
237       {\r
238         if (index < 0 || index >= Count)\r
239           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
240 \r
241         object obj = this[index];\r
242         if (obj == null)\r
243           return 0;\r
244         if (obj is PdfInteger)\r
245           return ((PdfInteger)obj).Value;\r
246         if (obj is PdfIntegerObject)\r
247           return ((PdfIntegerObject)obj).Value;\r
248         throw new InvalidCastException("GetInteger: Object is not an integer.");\r
249       }\r
250 \r
251       /// <summary>\r
252       /// Converts the specified value to double.\r
253       /// If the value not exists, the function returns 0.\r
254       /// If the value is not convertible, the function throws an InvalidCastException.\r
255       /// If the index is out of range, the function throws an ArgumentOutOfRangeException.\r
256       /// </summary>\r
257       public double GetReal(int index)\r
258       {\r
259         if (index < 0 || index >= Count)\r
260           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
261 \r
262         object obj = this[index];\r
263         if (obj == null)\r
264           return 0;\r
265         if (obj is PdfReal)\r
266           return ((PdfReal)obj).Value;\r
267         else if (obj is PdfRealObject)\r
268           return ((PdfRealObject)obj).Value;\r
269         else if (obj is PdfInteger)\r
270           return ((PdfInteger)obj).Value;\r
271         else if (obj is PdfIntegerObject)\r
272           return ((PdfIntegerObject)obj).Value;\r
273         throw new InvalidCastException("GetReal: Object is not a number.");\r
274       }\r
275 \r
276       /// <summary>\r
277       /// Converts the specified value to string.\r
278       /// If the value not exists, the function returns the empty string.\r
279       /// If the value is not convertible, the function throws an InvalidCastException.\r
280       /// If the index is out of range, the function throws an ArgumentOutOfRangeException.\r
281       /// </summary>\r
282       public string GetString(int index)\r
283       {\r
284         if (index < 0 || index >= Count)\r
285           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
286 \r
287         object obj = this[index];\r
288         if (obj == null)\r
289           return "";\r
290         if (obj is PdfString)\r
291           return ((PdfString)obj).Value;\r
292         if (obj is PdfStringObject)\r
293           return ((PdfStringObject)obj).Value;\r
294         throw new InvalidCastException("GetString: Object is not an integer.");\r
295       }\r
296 \r
297       /// <summary>\r
298       /// Converts the specified value to a name.\r
299       /// If the value not exists, the function returns the empty string.\r
300       /// If the value is not convertible, the function throws an InvalidCastException.\r
301       /// If the index is out of range, the function throws an ArgumentOutOfRangeException.\r
302       /// </summary>\r
303       public string GetName(int index)\r
304       {\r
305         if (index < 0 || index >= Count)\r
306           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
307 \r
308         object obj = this[index];\r
309         if (obj == null)\r
310           return "";\r
311         if (obj is PdfName)\r
312           return ((PdfName)obj).Value;\r
313         if (obj is PdfNameObject)\r
314           return ((PdfNameObject)obj).Value;\r
315         throw new InvalidCastException("GetName: Object is not an integer.");\r
316       }\r
317 \r
318       /// <summary>\r
319       /// Returns the indirect object if the value at the specified index is a PdfReference.\r
320       /// </summary>\r
321       [Obsolete("Use GetObject, GetDictionary, GetArray, or GetReference")]\r
322       public PdfObject GetIndirectObject(int index)\r
323       {\r
324         if (index < 0 || index >= Count)\r
325           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
326 \r
327         PdfItem item = this[index];\r
328         if (item is PdfReference)\r
329           return ((PdfReference)item).Value;\r
330         return null;\r
331       }\r
332 \r
333       /// <summary>\r
334       /// Gets the PdfObject with the specified index, or null, if no such object exists. If the index refers to\r
335       /// a reference, the referenced PdfObject is returned.\r
336       /// </summary>\r
337       public PdfObject GetObject(int index)\r
338       {\r
339         if (index < 0 || index >= Count)\r
340           throw new ArgumentOutOfRangeException("index", index, PSSR.IndexOutOfRange);\r
341 \r
342         PdfItem item = this[index];\r
343         if (item is PdfReference)\r
344           return ((PdfReference)item).Value;\r
345         return item as PdfObject;\r
346       }\r
347 \r
348       /// <summary>\r
349       /// Gets the PdfArray with the specified index, or null, if no such object exists. If the index refers to\r
350       /// a reference, the referenced PdfArray is returned.\r
351       /// </summary>\r
352       public PdfDictionary GetDictionary(int index)\r
353       {\r
354         return GetObject(index) as PdfDictionary;\r
355       }\r
356 \r
357       /// <summary>\r
358       /// Gets the PdfArray with the specified index, or null, if no such object exists. If the index refers to\r
359       /// a reference, the referenced PdfArray is returned.\r
360       /// </summary>\r
361       public PdfArray GetArray(int index)\r
362       {\r
363         return GetObject(index) as PdfArray;\r
364       }\r
365 \r
366       /// <summary>\r
367       /// Gets the PdfReference with the specified index, or null, if no such object exists.\r
368       /// </summary>\r
369       public PdfReference GetReference(int index)\r
370       {\r
371         PdfItem item = this[index];\r
372         return item as PdfReference;\r
373       }\r
374 \r
375       /// <summary>\r
376       /// Gets all items of this array.\r
377       /// </summary>\r
378       public PdfItem[] Items\r
379       {\r
380         get { return this.elements.ToArray(); }\r
381       }\r
382 \r
383       ///// <summary>\r
384       ///// INTERNAL USE ONLY.\r
385       ///// </summary>\r
386       //public List<PdfItem> GetArrayList_()\r
387       //{\r
388       //  // I use this hack to order the pages by ZIP code (MigraDoc ControlCode-Generator)\r
389       //  // TODO: implement a clean solution\r
390       //  return this.elements;\r
391       //}\r
392 \r
393       #region IList Members\r
394 \r
395       /// <summary>\r
396       /// Returns false.\r
397       /// </summary>\r
398       public bool IsReadOnly\r
399       {\r
400         get { return false; }\r
401       }\r
402 \r
403       //object IList.this[int index]\r
404       //{\r
405       //  get { return this.elements[index]; }\r
406       //  set { this.elements[index] = value as PdfItem; }\r
407       //}\r
408 \r
409       /// <summary>\r
410       /// Gets or sets an item at the specified index.\r
411       /// </summary>\r
412       /// <value></value>\r
413       public PdfItem this[int index]\r
414       {\r
415         get { return this.elements[index]; }\r
416         set\r
417         {\r
418           if (value == null)\r
419             throw new ArgumentNullException("value");\r
420           this.elements[index] = value;\r
421         }\r
422       }\r
423 \r
424       /// <summary>\r
425       /// Removes the item at the specified index.\r
426       /// </summary>\r
427       public void RemoveAt(int index)\r
428       {\r
429         this.elements.RemoveAt(index);\r
430       }\r
431 \r
432       /// <summary>\r
433       /// Removes the first occurrence of a specific object from the array/>.\r
434       /// </summary>\r
435       public bool Remove(PdfItem item)\r
436       {\r
437         return this.elements.Remove(item);\r
438       }\r
439 \r
440       /// <summary>\r
441       /// Inserts the item the specified index.\r
442       /// </summary>\r
443       public void Insert(int index, PdfItem value)\r
444       {\r
445         this.elements.Insert(index, value);\r
446       }\r
447 \r
448       /// <summary>\r
449       /// Determines whether the specified value is in the array.\r
450       /// </summary>\r
451       public bool Contains(PdfItem value)\r
452       {\r
453         return this.elements.Contains(value);\r
454       }\r
455 \r
456       /// <summary>\r
457       /// Removes all items from the array.\r
458       /// </summary>\r
459       public void Clear()\r
460       {\r
461         this.elements.Clear();\r
462       }\r
463 \r
464       /// <summary>\r
465       /// Gets the index of the specified item.\r
466       /// </summary>\r
467       public int IndexOf(PdfItem value)\r
468       {\r
469         return this.elements.IndexOf(value);\r
470       }\r
471 \r
472       /// <summary>\r
473       /// Appends the specified object to the array.\r
474       /// </summary>\r
475       public void Add(PdfItem value)\r
476       {\r
477         // TODO: ??? \r
478         //Debug.Assert((value is PdfObject && ((PdfObject)value).Reference == null) | !(value is PdfObject),\r
479         //  "You try to set an indirect object directly into an array.");\r
480 \r
481         PdfObject obj = value as PdfObject;\r
482         if (obj != null && obj.IsIndirect)\r
483           this.elements.Add(obj.Reference);\r
484         else\r
485           this.elements.Add(value);\r
486       }\r
487 \r
488       /// <summary>\r
489       /// Returns false.\r
490       /// </summary>\r
491       public bool IsFixedSize\r
492       {\r
493         get { return false; }\r
494       }\r
495 \r
496       #endregion\r
497 \r
498       #region ICollection Members\r
499 \r
500       /// <summary>\r
501       /// Returns false.\r
502       /// </summary>\r
503       public bool IsSynchronized\r
504       {\r
505         get { return false; }\r
506       }\r
507 \r
508       /// <summary>\r
509       /// Gets the number of elements in the array.\r
510       /// </summary>\r
511       public int Count\r
512       {\r
513         get { return this.elements.Count; }\r
514       }\r
515 \r
516       /// <summary>\r
517       /// Copies the elements of the array to the specified array.\r
518       /// </summary>\r
519       public void CopyTo(PdfItem[] array, int index)\r
520       {\r
521         this.elements.CopyTo(array, index);\r
522       }\r
523 \r
524       /// <summary>\r
525       /// The current implementation return null.\r
526       /// </summary>\r
527       public object SyncRoot\r
528       {\r
529         get { return null; }\r
530       }\r
531 \r
532       #endregion\r
533 \r
534       /// <summary>\r
535       /// Returns an enumerator that iterates through the array.\r
536       /// </summary>\r
537       public IEnumerator<PdfItem> GetEnumerator()\r
538       {\r
539         return this.elements.GetEnumerator();\r
540       }\r
541 \r
542       IEnumerator IEnumerable.GetEnumerator()\r
543       {\r
544         return this.elements.GetEnumerator();\r
545       }\r
546     }\r
547   }\r
548 }\r