1 /*
2  * $Id$
3  *
4  * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
5  *
6  * The contents of this file are subject to the Mozilla Public License Version 1.1
7  * (the "License"); you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the License.
13  *
14  * The Original Code is 'iText, a free JAVA-PDF library'.
15  *
16  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18  * All Rights Reserved.
19  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21  *
22  * Contributor(s): all the names of the contributors are added in the source code
23  * where applicable.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27  * provisions of LGPL are applicable instead of those above.  If you wish to
28  * allow use of your version of this file only under the terms of the LGPL
29  * License and not to allow others to use your version of this file under
30  * the MPL, indicate your decision by deleting the provisions above and
31  * replace them with the notice and other provisions required by the LGPL.
32  * If you do not delete the provisions above, a recipient may use your version
33  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34  *
35  * This library is free software; you can redistribute it and/or modify it
36  * under the terms of the MPL as stated above or under the terms of the GNU
37  * Library General Public License as published by the Free Software Foundation;
38  * either version 2 of the License, or any later version.
39  *
40  * This library is distributed in the hope that it will be useful, but WITHOUT
41  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43  * details.
44  *
45  * If you didn't download this code from the following link, you should check if
46  * you aren't using an obsolete version:
47  * http://www.lowagie.com/iText/
48  */
49 
50 package com.lowagie.text.pdf;
51 
52 import java.io.IOException;
53 import java.io.OutputStream;
54 import java.util.ArrayList;
55 import java.util.Iterator;
56 import java.util.ListIterator;
57 
58 /**
59  * <CODE>PdfArray</CODE> is the PDF Array object.
60  * <P>
61  * An array is a sequence of PDF objects. An array may contain a mixture of
62  * object types.
63  * An array is written as a left square bracket ([), followed by a sequence of
64  * objects, followed by a right square bracket (]).<BR>
65  * This object is described in the 'Portable Document Format Reference Manual
66  * version 1.7' section 3.2.5 (page 58).
67  *
68  * @see		PdfObject
69  */
70 public class PdfArray extends PdfObject {
71 
72 	// CLASS VARIABLES
73 
74 	/** this is the actual array of PdfObjects */
75     protected ArrayList arrayList;
76 
77     // constructors
78 
79     /**
80      * Constructs an empty <CODE>PdfArray</CODE>-object.
81      */
PdfArray()82     public PdfArray() {
83         super(ARRAY);
84         arrayList = new ArrayList();
85     }
86 
87     /**
88      * Constructs an <CODE>PdfArray</CODE>-object, containing 1
89      * <CODE>PdfObject</CODE>.
90      *
91      * @param	object		a <CODE>PdfObject</CODE> that has to be added to the array
92      */
PdfArray(PdfObject object)93     public PdfArray(PdfObject object) {
94         super(ARRAY);
95         arrayList = new ArrayList();
96         arrayList.add(object);
97     }
98 
99     /**
100      * Constructs a <CODE>PdfArray</CODE>-object, containing all
101      * <CODE>float</CODE> values in a specified array.
102      *
103      * The <CODE>float</CODE> values are internally converted to
104      * <CODE>PdfNumber</CODE> objects.
105      *
106      * @param values    an array of <CODE>float</CODE> values to be added
107      */
PdfArray(float values[])108     public PdfArray(float values[]) {
109         super(ARRAY);
110         arrayList = new ArrayList();
111         add(values);
112     }
113 
114     /**
115      * Constructs a <CODE>PdfArray</CODE>-object, containing all
116      * <CODE>int</CODE> values in a specified array.
117      *
118      * The <CODE>int</CODE> values are internally converted to
119      * <CODE>PdfNumber</CODE> objects.
120      *
121      * @param values    an array of <CODE>int</CODE> values to be added
122      */
PdfArray(int values[])123     public PdfArray(int values[]) {
124         super(ARRAY);
125         arrayList = new ArrayList();
126         add(values);
127     }
128 
129     /**
130      * Constructs a <CODE>PdfArray</CODE>, containing all elements of a
131      * specified <CODE>ArrayList</CODE>.
132      *
133      * @param l    an <CODE>ArrayList</CODE> with <CODE>PdfObject</CODE>s to be
134      *   added to the array
135      * @throws ClassCastException if the <CODE>ArrayList</CODE> contains
136      *   something that isn't a <CODE>PdfObject</CODE>
137      * @since 2.1.3
138      */
PdfArray(ArrayList l)139     public PdfArray(ArrayList l) {
140         this();
141         for (Iterator i = l.iterator(); i.hasNext(); )
142         	add((PdfObject)i.next());
143     }
144 
145     /**
146      * Constructs an <CODE>PdfArray</CODE>-object, containing all
147      * <CODE>PdfObject</CODE>s in a specified <CODE>PdfArray</CODE>.
148      *
149      * @param array    a <CODE>PdfArray</CODE> to be added to the array
150      */
PdfArray(PdfArray array)151     public PdfArray(PdfArray array) {
152         super(ARRAY);
153         arrayList = new ArrayList(array.arrayList);
154     }
155 
156     // METHODS OVERRIDING SOME PDFOBJECT METHODS
157 
158     /**
159      * Writes the PDF representation of this <CODE>PdfArray</CODE> as an array
160      * of <CODE>byte</CODE> to the specified <CODE>OutputStream</CODE>.
161      *
162      * @param writer for backwards compatibility
163      * @param os the <CODE>OutputStream</CODE> to write the bytes to.
164      */
toPdf(PdfWriter writer, OutputStream os)165     public void toPdf(PdfWriter writer, OutputStream os) throws IOException {
166         os.write('[');
167 
168         Iterator i = arrayList.iterator();
169         PdfObject object;
170         int type = 0;
171         if (i.hasNext()) {
172             object = (PdfObject) i.next();
173             if (object == null)
174                 object = PdfNull.PDFNULL;
175             object.toPdf(writer, os);
176         }
177         while (i.hasNext()) {
178             object = (PdfObject) i.next();
179             if (object == null)
180                 object = PdfNull.PDFNULL;
181             type = object.type();
182             if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING)
183                 os.write(' ');
184             object.toPdf(writer, os);
185         }
186         os.write(']');
187     }
188 
189     /**
190      * Returns a string representation of this <CODE>PdfArray</CODE>.
191      *
192      * The string representation consists of a list of all
193      * <CODE>PdfObject</CODE>s contained in this <CODE>PdfArray</CODE>,
194      * enclosed in square brackets ("[]"). Adjacent elements are separated
195      * by the characters ", " (comma and space).
196      *
197      * @return the string representation of this <CODE>PdfArray</CODE>
198      */
toString()199     public String toString() {
200     	return arrayList.toString();
201     }
202 
203     // ARRAY CONTENT METHODS
204 
205     /**
206      * Overwrites a specified location of the array, returning the previous
207      * value
208      *
209      * @param idx The index of the element to be overwritten
210      * @param obj new value for the specified index
211      * @throws IndexOutOfBoundsException if the specified position doesn't exist
212      * @return the previous value
213      * @since 2.1.5
214      */
set(int idx, PdfObject obj)215     public PdfObject set(int idx, PdfObject obj) {
216         return (PdfObject) arrayList.set(idx, obj);
217     }
218 
219     /**
220      * Remove the element at the specified position from the array.
221      *
222      * Shifts any subsequent elements to the left (subtracts one from their
223      * indices).
224      *
225      * @param idx The index of the element to be removed.
226      * @throws IndexOutOfBoundsException the specified position doesn't exist
227      * @since 2.1.5
228      */
remove(int idx)229     public PdfObject remove(int idx) {
230         return (PdfObject) arrayList.remove(idx);
231     }
232 
233     /**
234      * Get the internal arrayList for this PdfArray.  Not Recommended.
235      *
236      * @deprecated
237      * @return the internal ArrayList.  Naughty Naughty.
238      */
getArrayList()239     public ArrayList getArrayList() {
240         return arrayList;
241     }
242 
243     /**
244      * Returns the number of entries in the array.
245      *
246      * @return		the size of the ArrayList
247      */
size()248     public int size() {
249         return arrayList.size();
250     }
251 
252     /**
253      * Returns <CODE>true</CODE> if the array is empty.
254      *
255      * @return <CODE>true</CODE> if the array is empty
256      * @since 2.1.5
257      */
isEmpty()258     public boolean isEmpty() {
259         return arrayList.isEmpty();
260     }
261 
262     /**
263      * Adds a <CODE>PdfObject</CODE> to the end of the <CODE>PdfArray</CODE>.
264      *
265      * The <CODE>PdfObject</CODE> will be the last element.
266      *
267      * @param object <CODE>PdfObject</CODE> to add
268      * @return always <CODE>true</CODE>
269      */
add(PdfObject object)270     public boolean add(PdfObject object) {
271         return arrayList.add(object);
272     }
273 
274     /**
275      * Adds an array of <CODE>float</CODE> values to end of the
276      * <CODE>PdfArray</CODE>.
277      *
278      * The values will be the last elements.
279      * The <CODE>float</CODE> values are internally converted to
280      * <CODE>PdfNumber</CODE> objects.
281      *
282      * @param values An array of <CODE>float</CODE> values to add
283      * @return always <CODE>true</CODE>
284      */
add(float values[])285     public boolean add(float values[]) {
286         for (int k = 0; k < values.length; ++k)
287             arrayList.add(new PdfNumber(values[k]));
288         return true;
289     }
290 
291     /**
292      * Adds an array of <CODE>int</CODE> values to end of the <CODE>PdfArray</CODE>.
293      *
294      * The values will be the last elements.
295      * The <CODE>int</CODE> values are internally converted to
296      * <CODE>PdfNumber</CODE> objects.
297      *
298      * @param values An array of <CODE>int</CODE> values to add
299      * @return always <CODE>true</CODE>
300      */
add(int values[])301     public boolean add(int values[]) {
302         for (int k = 0; k < values.length; ++k)
303             arrayList.add(new PdfNumber(values[k]));
304         return true;
305     }
306 
307     /**
308      * Inserts the specified element at the specified position.
309      *
310      * Shifts the element currently at that position (if any) and
311      * any subsequent elements to the right (adds one to their indices).
312      *
313      * @param index The index at which the specified element is to be inserted
314      * @param element The element to be inserted
315      * @throws IndexOutOfBoundsException if the specified index is larger than the
316      *   last position currently set, plus 1.
317      * @since 2.1.5
318      */
add(int index, PdfObject element)319     public void add(int index, PdfObject element) {
320         arrayList.add(index, element);
321     }
322 
323     /**
324      * Inserts a <CODE>PdfObject</CODE> at the beginning of the
325      * <CODE>PdfArray</CODE>.
326      *
327      * The <CODE>PdfObject</CODE> will be the first element, any other elements
328      * will be shifted to the right (adds one to their indices).
329      *
330      * @param object The <CODE>PdfObject</CODE> to add
331      */
addFirst(PdfObject object)332     public void addFirst(PdfObject object) {
333         arrayList.add(0, object);
334     }
335 
336     /**
337      * Checks if the <CODE>PdfArray</CODE> already contains a certain
338      * <CODE>PdfObject</CODE>.
339      *
340      * @param object The <CODE>PdfObject</CODE> to check
341      * @return <CODE>true</CODE>
342      */
contains(PdfObject object)343     public boolean contains(PdfObject object) {
344         return arrayList.contains(object);
345     }
346 
347     /**
348      * Returns the list iterator for the array.
349      *
350      * @return a ListIterator
351      */
listIterator()352     public ListIterator listIterator() {
353         return arrayList.listIterator();
354     }
355 
356     /**
357      * Returns the <CODE>PdfObject</CODE> with the specified index.
358      *
359      * A possible indirect references is not resolved, so the returned
360      * <CODE>PdfObject</CODE> may be either a direct object or an indirect
361      * reference, depending on how the object is stored in the
362      * <CODE>PdfArray</CODE>.
363      *
364      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
365      * @return A <CODE>PdfObject</CODE>
366      */
getPdfObject(int idx)367     public PdfObject getPdfObject(int idx) {
368         return (PdfObject)arrayList.get(idx);
369     }
370 
371     /**
372      * Returns the <CODE>PdfObject</CODE> with the specified index, resolving
373      * a possible indirect reference to a direct object.
374      *
375      * Thus this method will never return a <CODE>PdfIndirectReference</CODE>
376      * object.
377      *
378      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
379      * @return A direct <CODE>PdfObject</CODE> or <CODE>null</CODE>
380      */
getDirectObject(int idx)381     public PdfObject getDirectObject(int idx) {
382         return PdfReader.getPdfObject(getPdfObject(idx));
383     }
384 
385     // DOWNCASTING GETTERS
386     // @author Mark A Storer (2/17/06)
387 
388     /**
389      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfDictionary</CODE>,
390      * resolving indirect references.
391      *
392      * The object corresponding to the specified index is retrieved and
393      * resolvedto a direct object.
394      * If it is a <CODE>PdfDictionary</CODE>, it is cast down and returned as such.
395      * Otherwise <CODE>null</CODE> is returned.
396      *
397      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
398      * @return the corresponding <CODE>PdfDictionary</CODE> object,
399      *   or <CODE>null</CODE>
400      */
getAsDict(int idx)401     public PdfDictionary getAsDict(int idx) {
402         PdfDictionary dict = null;
403         PdfObject orig = getDirectObject(idx);
404         if (orig != null && orig.isDictionary())
405             dict = (PdfDictionary) orig;
406         return dict;
407     }
408 
409     /**
410      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfArray</CODE>,
411      * resolving indirect references.
412      *
413      * The object corresponding to the specified index is retrieved and
414      * resolved to a direct object.
415      * If it is a <CODE>PdfArray</CODE>, it is cast down and returned as such.
416      * Otherwise <CODE>null</CODE> is returned.
417      *
418      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
419      * @return the corresponding <CODE>PdfArray</CODE> object,
420      *   or <CODE>null</CODE>
421      */
getAsArray(int idx)422     public PdfArray getAsArray(int idx) {
423         PdfArray array = null;
424         PdfObject orig = getDirectObject(idx);
425         if (orig != null && orig.isArray())
426             array = (PdfArray) orig;
427         return array;
428     }
429 
430     /**
431      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfStream</CODE>,
432      * resolving indirect references.
433      *
434      * The object corresponding to the specified index is retrieved and
435      * resolved to a direct object.
436      * If it is a <CODE>PdfStream</CODE>, it is cast down and returned as such.
437      * Otherwise <CODE>null</CODE> is returned.
438      *
439      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
440      * @return the corresponding <CODE>PdfStream</CODE> object,
441      *   or <CODE>null</CODE>
442      */
getAsStream(int idx)443     public PdfStream getAsStream(int idx) {
444         PdfStream stream = null;
445         PdfObject orig = getDirectObject(idx);
446         if (orig != null && orig.isStream())
447             stream = (PdfStream) orig;
448         return stream;
449     }
450 
451     /**
452      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfString</CODE>,
453      * resolving indirect references.
454      *
455      * The object corresponding to the specified index is retrieved and
456      * resolved to a direct object.
457      * If it is a <CODE>PdfString</CODE>, it is cast down and returned as such.
458      * Otherwise <CODE>null</CODE> is returned.
459      *
460      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
461      * @return the corresponding <CODE>PdfString</CODE> object,
462      *   or <CODE>null</CODE>
463      */
getAsString(int idx)464     public PdfString getAsString(int idx) {
465         PdfString string = null;
466         PdfObject orig = getDirectObject(idx);
467         if (orig != null && orig.isString())
468             string = (PdfString) orig;
469         return string;
470     }
471 
472     /**
473      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfNumber</CODE>,
474      * resolving indirect references.
475      *
476      * The object corresponding to the specified index is retrieved and
477      * resolved to a direct object.
478      * If it is a <CODE>PdfNumber</CODE>, it is cast down and returned as such.
479      * Otherwise <CODE>null</CODE> is returned.
480      *
481      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
482      * @return the corresponding <CODE>PdfNumber</CODE> object,
483      *   or <CODE>null</CODE>
484      */
getAsNumber(int idx)485     public PdfNumber getAsNumber(int idx) {
486         PdfNumber number = null;
487         PdfObject orig = getDirectObject(idx);
488         if (orig != null && orig.isNumber())
489             number = (PdfNumber) orig;
490         return number;
491     }
492 
493     /**
494      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfName</CODE>,
495      * resolving indirect references.
496      *
497      * The object corresponding to the specified index is retrieved and
498      * resolved to a direct object.
499      * If it is a <CODE>PdfName</CODE>, it is cast down and returned as such.
500      * Otherwise <CODE>null</CODE> is returned.
501      *
502      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
503      * @return the corresponding <CODE>PdfName</CODE> object,
504      *   or <CODE>null</CODE>
505      */
getAsName(int idx)506     public PdfName getAsName(int idx) {
507         PdfName name = null;
508         PdfObject orig = getDirectObject(idx);
509         if (orig != null && orig.isName())
510             name = (PdfName) orig;
511         return name;
512     }
513 
514     /**
515      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfBoolean</CODE>,
516      * resolving indirect references.
517      *
518      * The object corresponding to the specified index is retrieved and
519      * resolved to a direct object.
520      * If it is a <CODE>PdfBoolean</CODE>, it is cast down and returned as
521      * such. Otherwise <CODE>null</CODE> is returned.
522      *
523      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
524      * @return the corresponding <CODE>PdfBoolean</CODE> object,
525      *   or <CODE>null</CODE>
526      */
getAsBoolean(int idx)527     public PdfBoolean getAsBoolean(int idx) {
528         PdfBoolean bool = null;
529         PdfObject orig = getDirectObject(idx);
530         if (orig != null && orig.isBoolean())
531             bool = (PdfBoolean) orig;
532         return bool;
533     }
534 
535     /**
536      * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfIndirectReference</CODE>.
537      *
538      * The object corresponding to the specified index is retrieved.
539      * If it is a <CODE>PdfIndirectReference</CODE>, it is cast down and
540      * returned as such. Otherwise <CODE>null</CODE> is returned.
541      *
542      * @param idx The index of the <CODE>PdfObject</CODE> to be returned
543      * @return the corresponding <CODE>PdfIndirectReference</CODE> object,
544      *   or <CODE>null</CODE>
545      */
getAsIndirectObject(int idx)546     public PdfIndirectReference getAsIndirectObject(int idx) {
547         PdfIndirectReference ref = null;
548         PdfObject orig = getPdfObject(idx); // not getDirect this time.
549         if (orig != null && orig.isIndirect())
550             ref = (PdfIndirectReference) orig;
551         return ref;
552     }
553 }
554