001: /**
002: * Copyright (c) 2003-2006, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.common;
031:
032: import org.pdfbox.cos.COSArray;
033: import org.pdfbox.cos.COSBase;
034: import org.pdfbox.cos.COSDictionary;
035: import org.pdfbox.cos.COSInteger;
036: import org.pdfbox.cos.COSFloat;
037: import org.pdfbox.cos.COSString;
038: import org.pdfbox.cos.COSName;
039: import org.pdfbox.cos.COSNull;
040: import org.pdfbox.cos.COSNumber;
041:
042: import java.util.ArrayList;
043: import java.util.Collection;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.ListIterator;
047:
048: /**
049: * This is an implementation of a List that will sync its contents to a COSArray.
050: *
051: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
052: * @version $Revision: 1.15 $
053: */
054: public class COSArrayList implements List {
055: private COSArray array;
056: private List actual;
057:
058: private COSDictionary parentDict;
059: private String dictKey;
060:
061: /**
062: * Default constructor.
063: */
064: public COSArrayList() {
065: array = new COSArray();
066: actual = new ArrayList();
067: }
068:
069: /**
070: * Constructor.
071: *
072: * @param actualList The list of standard java objects
073: * @param cosArray The COS array object to sync to.
074: */
075: public COSArrayList(List actualList, COSArray cosArray) {
076: actual = actualList;
077: array = cosArray;
078: }
079:
080: /**
081: * This is a really special constructor. Sometimes the PDF spec says
082: * that a dictionary entry can either be a single item or an array of those
083: * items. But in the PDModel interface we really just want to always return
084: * a java.util.List. In the case were we get the list and never modify it
085: * we don't want to convert to COSArray and put one element, unless we append
086: * to the list. So here we are going to create this object with a single
087: * item instead of a list, but allow more items to be added and then converted
088: * to an array.
089: *
090: * @param actualObject The PDModel object.
091: * @param item The COS Model object.
092: * @param dictionary The dictionary that holds the item, and will hold the array if an item is added.
093: * @param dictionaryKey The key into the dictionary to set the item.
094: */
095: public COSArrayList(Object actualObject, COSBase item,
096: COSDictionary dictionary, String dictionaryKey) {
097: array = new COSArray();
098: array.add(item);
099: actual = new ArrayList();
100: actual.add(actualObject);
101:
102: parentDict = dictionary;
103: dictKey = dictionaryKey;
104: }
105:
106: /**
107: * {@inheritDoc}
108: */
109: public int size() {
110: return actual.size();
111: }
112:
113: /**
114: * {@inheritDoc}
115: */
116: public boolean isEmpty() {
117: return actual.isEmpty();
118: }
119:
120: /**
121: * {@inheritDoc}
122: */
123: public boolean contains(Object o) {
124: return actual.contains(o);
125: }
126:
127: /**
128: * {@inheritDoc}
129: */
130: public Iterator iterator() {
131: return actual.iterator();
132: }
133:
134: /**
135: * {@inheritDoc}
136: */
137: public Object[] toArray() {
138: return actual.toArray();
139: }
140:
141: /**
142: * {@inheritDoc}
143: */
144: public Object[] toArray(Object[] a) {
145: return actual.toArray(a);
146:
147: }
148:
149: /**
150: * {@inheritDoc}
151: */
152: public boolean add(Object o) {
153: //when adding if there is a parentDict then change the item
154: //in the dictionary from a single item to an array.
155: if (parentDict != null) {
156: parentDict.setItem(dictKey, array);
157: //clear the parent dict so it doesn't happen again, there might be
158: //a usecase for keeping the parentDict around but not now.
159: parentDict = null;
160: }
161: //string is a special case because we can't subclass to be COSObjectable
162: if (o instanceof String) {
163: array.add(new COSString((String) o));
164: } else if (o instanceof DualCOSObjectable) {
165: DualCOSObjectable dual = (DualCOSObjectable) o;
166: array.add(dual.getFirstCOSObject());
167: array.add(dual.getSecondCOSObject());
168: } else {
169: array.add(((COSObjectable) o).getCOSObject());
170: }
171: return actual.add(o);
172: }
173:
174: /**
175: * {@inheritDoc}
176: */
177: public boolean remove(Object o) {
178: boolean retval = true;
179: int index = actual.indexOf(o);
180: if (index >= 0) {
181: actual.remove(index);
182: array.remove(index);
183: } else {
184: retval = false;
185: }
186: return retval;
187: }
188:
189: /**
190: * {@inheritDoc}
191: */
192: public boolean containsAll(Collection c) {
193: return actual.containsAll(c);
194: }
195:
196: /**
197: * {@inheritDoc}
198: */
199: public boolean addAll(Collection c) {
200: //when adding if there is a parentDict then change the item
201: //in the dictionary from a single item to an array.
202: if (parentDict != null && c.size() > 0) {
203: parentDict.setItem(dictKey, array);
204: //clear the parent dict so it doesn't happen again, there might be
205: //a usecase for keeping the parentDict around but not now.
206: parentDict = null;
207: }
208: array.addAll(toCOSObjectList(c));
209: return actual.addAll(c);
210: }
211:
212: /**
213: * {@inheritDoc}
214: */
215: public boolean addAll(int index, Collection c) {
216: //when adding if there is a parentDict then change the item
217: //in the dictionary from a single item to an array.
218: if (parentDict != null && c.size() > 0) {
219: parentDict.setItem(dictKey, array);
220: //clear the parent dict so it doesn't happen again, there might be
221: //a usecase for keeping the parentDict around but not now.
222: parentDict = null;
223: }
224:
225: if (c.size() > 0 && c.toArray()[0] instanceof DualCOSObjectable) {
226: array.addAll(index * 2, toCOSObjectList(c));
227: } else {
228: array.addAll(index, toCOSObjectList(c));
229: }
230: return actual.addAll(index, c);
231: }
232:
233: /**
234: * This will take an array of COSNumbers and return a COSArrayList of
235: * java.lang.Integer values.
236: *
237: * @param intArray The existing integer Array.
238: *
239: * @return A list that is part of the core Java collections.
240: */
241: public static List convertIntegerCOSArrayToList(COSArray intArray) {
242: List numbers = new ArrayList();
243: for (int i = 0; i < intArray.size(); i++) {
244: numbers.add(new Integer(((COSNumber) intArray.get(i))
245: .intValue()));
246: }
247: return new COSArrayList(numbers, intArray);
248: }
249:
250: /**
251: * This will take an array of COSNumbers and return a COSArrayList of
252: * java.lang.Float values.
253: *
254: * @param floatArray The existing float Array.
255: *
256: * @return The list of Float objects.
257: */
258: public static List convertFloatCOSArrayToList(COSArray floatArray) {
259: List retval = null;
260: if (floatArray != null) {
261: List numbers = new ArrayList();
262: for (int i = 0; i < floatArray.size(); i++) {
263: numbers.add(new Float(((COSNumber) floatArray.get(i))
264: .floatValue()));
265: }
266: retval = new COSArrayList(numbers, floatArray);
267: }
268: return retval;
269: }
270:
271: /**
272: * This will take an array of COSName and return a COSArrayList of
273: * java.lang.String values.
274: *
275: * @param nameArray The existing name Array.
276: *
277: * @return The list of String objects.
278: */
279: public static List convertCOSNameCOSArrayToList(COSArray nameArray) {
280: List retval = null;
281: if (nameArray != null) {
282: List names = new ArrayList();
283: for (int i = 0; i < nameArray.size(); i++) {
284: names.add(((COSName) nameArray.getObject(i)).getName());
285: }
286: retval = new COSArrayList(names, nameArray);
287: }
288: return retval;
289: }
290:
291: /**
292: * This will take an array of COSString and return a COSArrayList of
293: * java.lang.String values.
294: *
295: * @param stringArray The existing name Array.
296: *
297: * @return The list of String objects.
298: */
299: public static List convertCOSStringCOSArrayToList(
300: COSArray stringArray) {
301: List retval = null;
302: if (stringArray != null) {
303: List string = new ArrayList();
304: for (int i = 0; i < stringArray.size(); i++) {
305: string.add(((COSString) stringArray.getObject(i))
306: .getString());
307: }
308: retval = new COSArrayList(string, stringArray);
309: }
310: return retval;
311: }
312:
313: /**
314: * This will take an list of string objects and return a COSArray of COSName
315: * objects.
316: *
317: * @param strings A list of strings
318: *
319: * @return An array of COSName objects
320: */
321: public static COSArray convertStringListToCOSNameCOSArray(
322: List strings) {
323: COSArray retval = new COSArray();
324: for (int i = 0; i < strings.size(); i++) {
325: Object next = strings.get(i);
326: if (next instanceof COSName) {
327: retval.add((COSName) next);
328: } else {
329: retval.add(COSName.getPDFName((String) next));
330: }
331: }
332: return retval;
333: }
334:
335: /**
336: * This will take an list of string objects and return a COSArray of COSName
337: * objects.
338: *
339: * @param strings A list of strings
340: *
341: * @return An array of COSName objects
342: */
343: public static COSArray convertStringListToCOSStringCOSArray(
344: List strings) {
345: COSArray retval = new COSArray();
346: for (int i = 0; i < strings.size(); i++) {
347: retval.add(new COSString((String) strings.get(i)));
348: }
349: return retval;
350: }
351:
352: /**
353: * This will convert a list of COSObjectables to an
354: * array list of COSBase objects.
355: *
356: * @param cosObjectableList A list of COSObjectable.
357: *
358: * @return A list of COSBase.
359: */
360: public static COSArray converterToCOSArray(List cosObjectableList) {
361: COSArray array = null;
362: if (cosObjectableList != null) {
363: if (cosObjectableList instanceof COSArrayList) {
364: //if it is already a COSArrayList then we don't want to recreate the array, we want to reuse it.
365: array = ((COSArrayList) cosObjectableList).array;
366: } else {
367: array = new COSArray();
368: Iterator iter = cosObjectableList.iterator();
369: while (iter.hasNext()) {
370: Object next = iter.next();
371: if (next instanceof String) {
372: array.add(new COSString((String) next));
373: } else if (next instanceof Integer
374: || next instanceof Long) {
375: array.add(new COSInteger(((Number) next)
376: .longValue()));
377: } else if (next instanceof Float
378: || next instanceof Double) {
379: array.add(new COSFloat(((Number) next)
380: .floatValue()));
381: } else if (next instanceof COSObjectable) {
382: COSObjectable object = (COSObjectable) next;
383: array.add(object.getCOSObject());
384: } else if (next instanceof DualCOSObjectable) {
385: DualCOSObjectable object = (DualCOSObjectable) next;
386: array.add(object.getFirstCOSObject());
387: array.add(object.getSecondCOSObject());
388: } else if (next == null) {
389: array.add(COSNull.NULL);
390: } else {
391: throw new RuntimeException(
392: "Error: Don't know how to convert type to COSBase '"
393: + next.getClass().getName()
394: + "'");
395: }
396: }
397: }
398: }
399: return array;
400: }
401:
402: private List toCOSObjectList(Collection list) {
403: List cosObjects = new ArrayList();
404: Iterator iter = list.iterator();
405: while (iter.hasNext()) {
406: Object next = iter.next();
407: if (next instanceof String) {
408: cosObjects.add(new COSString((String) next));
409: } else if (next instanceof DualCOSObjectable) {
410: DualCOSObjectable object = (DualCOSObjectable) next;
411: array.add(object.getFirstCOSObject());
412: array.add(object.getSecondCOSObject());
413: } else {
414: COSObjectable cos = (COSObjectable) next;
415: cosObjects.add(cos.getCOSObject());
416: }
417: }
418: return cosObjects;
419: }
420:
421: /**
422: * {@inheritDoc}
423: */
424: public boolean removeAll(Collection c) {
425: array.removeAll(toCOSObjectList(c));
426: return actual.removeAll(c);
427: }
428:
429: /**
430: * {@inheritDoc}
431: */
432: public boolean retainAll(Collection c) {
433: array.retainAll(toCOSObjectList(c));
434: return actual.retainAll(c);
435: }
436:
437: /**
438: * {@inheritDoc}
439: */
440: public void clear() {
441: //when adding if there is a parentDict then change the item
442: //in the dictionary from a single item to an array.
443: if (parentDict != null) {
444: parentDict.setItem(dictKey, (COSBase) null);
445: }
446: actual.clear();
447: array.clear();
448: }
449:
450: /**
451: * {@inheritDoc}
452: */
453: public boolean equals(Object o) {
454: return actual.equals(o);
455: }
456:
457: /**
458: * {@inheritDoc}
459: */
460: public int hashCode() {
461: return actual.hashCode();
462: }
463:
464: /**
465: * {@inheritDoc}
466: */
467: public Object get(int index) {
468: return actual.get(index);
469:
470: }
471:
472: /**
473: * {@inheritDoc}
474: */
475: public Object set(int index, Object element) {
476: if (element instanceof String) {
477: COSString item = new COSString((String) element);
478: if (parentDict != null && index == 0) {
479: parentDict.setItem(dictKey, item);
480: }
481: array.set(index, item);
482: } else if (element instanceof DualCOSObjectable) {
483: DualCOSObjectable dual = (DualCOSObjectable) element;
484: array.set(index * 2, dual.getFirstCOSObject());
485: array.set(index * 2 + 1, dual.getSecondCOSObject());
486: } else {
487: if (parentDict != null && index == 0) {
488: parentDict.setItem(dictKey, ((COSObjectable) element)
489: .getCOSObject());
490: }
491: array.set(index, ((COSObjectable) element).getCOSObject());
492: }
493: return actual.set(index, element);
494: }
495:
496: /**
497: * {@inheritDoc}
498: */
499: public void add(int index, Object element) {
500: //when adding if there is a parentDict then change the item
501: //in the dictionary from a single item to an array.
502: if (parentDict != null) {
503: parentDict.setItem(dictKey, array);
504: //clear the parent dict so it doesn't happen again, there might be
505: //a usecase for keeping the parentDict around but not now.
506: parentDict = null;
507: }
508: actual.add(index, element);
509: if (element instanceof String) {
510: array.add(index, new COSString((String) element));
511: } else if (element instanceof DualCOSObjectable) {
512: DualCOSObjectable dual = (DualCOSObjectable) element;
513: array.add(index * 2, dual.getFirstCOSObject());
514: array.add(index * 2 + 1, dual.getSecondCOSObject());
515: } else {
516: array.add(index, ((COSObjectable) element).getCOSObject());
517: }
518: }
519:
520: /**
521: * {@inheritDoc}
522: */
523: public Object remove(int index) {
524: if (array.size() > index
525: && array.get(index) instanceof DualCOSObjectable) {
526: //remove both objects
527: array.remove(index);
528: array.remove(index);
529: } else {
530: array.remove(index);
531: }
532: return actual.remove(index);
533: }
534:
535: /**
536: * {@inheritDoc}
537: */
538: public int indexOf(Object o) {
539: return actual.indexOf(o);
540: }
541:
542: /**
543: * {@inheritDoc}
544: */
545: public int lastIndexOf(Object o) {
546: return actual.indexOf(o);
547:
548: }
549:
550: /**
551: * {@inheritDoc}
552: */
553: public ListIterator listIterator() {
554: return actual.listIterator();
555: }
556:
557: /**
558: * {@inheritDoc}
559: */
560: public ListIterator listIterator(int index) {
561: return actual.listIterator(index);
562: }
563:
564: /**
565: * {@inheritDoc}
566: */
567: public List subList(int fromIndex, int toIndex) {
568: return actual.subList(fromIndex, toIndex);
569: }
570: }
|