1 /*
2 * $Id: PdfDictionary.java 3762 2009-03-06 16:53:44Z blowagie $
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.HashMap;
55 import java.util.Iterator;
56 import java.util.Set;
57
58 /**
59 * <CODE>PdfDictionary</CODE> is the Pdf dictionary object.
60 * <P>
61 * A dictionary is an associative table containing pairs of objects.
62 * The first element of each pair is called the <I>key</I> and the second
63 * element is called the <I>value</I>.
64 * Unlike dictionaries in the PostScript language, a key must be a
65 * <CODE>PdfName</CODE>.
66 * A value can be any kind of <CODE>PdfObject</CODE>, including a dictionary.
67 * A dictionary is generally used to collect and tie together the attributes
68 * of a complex object, with each key-value pair specifying the name and value
69 * of an attribute.<BR>
70 * A dictionary is represented by two left angle brackets (<<), followed by a
71 * sequence of key-value pairs, followed by two right angle brackets (>>).<BR>
72 * This object is described in the 'Portable Document Format Reference Manual
73 * version 1.7' section 3.2.6 (page 59-60).
74 * <P>
75 *
76 * @see PdfObject
77 * @see PdfName
78 * @see BadPdfFormatException
79 */
80 public class PdfDictionary extends PdfObject {
81
82 // CONSTANTS
83
84 /** This is a possible type of dictionary */
85 public static final PdfName FONT = PdfName.FONT;
86
87 /** This is a possible type of dictionary */
88 public static final PdfName OUTLINES = PdfName.OUTLINES;
89
90 /** This is a possible type of dictionary */
91 public static final PdfName PAGE = PdfName.PAGE;
92
93 /** This is a possible type of dictionary */
94 public static final PdfName PAGES = PdfName.PAGES;
95
96 /** This is a possible type of dictionary */
97 public static final PdfName CATALOG = PdfName.CATALOG;
98
99 // CLASS VARIABLES
100
101 /** This is the type of this dictionary */
102 private PdfName dictionaryType = null;
103
104 /** This is the hashmap that contains all the values and keys of the dictionary */
105 protected HashMap hashMap;
106
107 // CONSTRUCTORS
108
109 /**
110 * Constructs an empty <CODE>PdfDictionary</CODE>-object.
111 */
112 public PdfDictionary() {
113 super(DICTIONARY);
114 hashMap = new HashMap();
115 }
116
117 /**
118 * Constructs a <CODE>PdfDictionary</CODE>-object of a certain type.
119 *
120 * @param type a <CODE>PdfName</CODE>
121 */
122 public PdfDictionary(PdfName type) {
123 this();
124 dictionaryType = type;
125 put(PdfName.TYPE, dictionaryType);
126 }
127
128 // METHODS OVERRIDING SOME PDFOBJECT METHODS
129
130 /**
131 * Writes the PDF representation of this <CODE>PdfDictionary</CODE> as an
132 * array of <CODE>byte</CODE> to the given <CODE>OutputStream</CODE>.
133 *
134 * @param writer for backwards compatibility
135 * @param os the <CODE>OutputStream</CODE> to write the bytes to.
136 * @throws IOException
137 */
138 public void toPdf(PdfWriter writer, OutputStream os) throws IOException {
139 os.write('<');
140 os.write('<');
141 // loop over all the object-pairs in the HashMap
142 PdfName key;
143 PdfObject value;
144 int type = 0;
145 for (Iterator i = hashMap.keySet().iterator(); i.hasNext(); ) {
146 key = (PdfName) i.next();
147 value = (PdfObject) hashMap.get(key);
148 key.toPdf(writer, os);
149 type = value.type();
150 if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING)
151 os.write(' ');
152 value.toPdf(writer, os);
153 }
154 os.write('>');
155 os.write('>');
156 }
157
158 /**
159 * Returns a string representation of this <CODE>PdfDictionary</CODE>.
160 *
161 * The string doesn't contain any of the content of this dictionary.
162 * Rather the string "dictionary" is returned, possibly followed by the
163 * type of this <CODE>PdfDictionary</CODE>, if set.
164 *
165 * @return the string representation of this <CODE>PdfDictionary</CODE>
166 * @see com.lowagie.text.pdf.PdfObject#toString()
167 */
168 public String toString() {
169 if (get(PdfName.TYPE) == null)
170 return "Dictionary";
171 return "Dictionary of type: " + get(PdfName.TYPE);
172 }
173
174 // DICTIONARY CONTENT METHODS
175
176 /**
177 * Associates the specified <CODE>PdfObject</CODE> as <VAR>value</VAR> with
178 * the specified <CODE>PdfName</CODE> as <VAR>key</VAR> in this map.
179 *
180 * If the map previously contained a mapping for this <VAR>key</VAR>, the
181 * old <VAR>value</VAR> is replaced. If the <VAR>value</VAR> is
182 * <CODE>null</CODE> or <CODE>PdfNull</CODE> the key is deleted.
183 *
184 * @param key a <CODE>PdfName</CODE>
185 * @param object the <CODE>PdfObject</CODE> to be associated with the
186 * <VAR>key</VAR>
187 */
188 public void put(PdfName key, PdfObject object) {
189 if (object == null || object.isNull())
190 hashMap.remove(key);
191 else
192 hashMap.put(key, object);
193 }
194
195 /**
196 * Associates the specified <CODE>PdfObject</CODE> as value to the
197 * specified <CODE>PdfName</CODE> as key in this map.
198 *
199 * If the <VAR>value</VAR> is a <CODE>PdfNull</CODE>, it is treated just as
200 * any other <CODE>PdfObject</CODE>. If the <VAR>value</VAR> is
201 * <CODE>null</CODE> however nothing is done.
202 *
203 * @param key a <CODE>PdfName</CODE>
204 * @param value the <CODE>PdfObject</CODE> to be associated to the
205 * <VAR>key</VAR>
206 */
207 public void putEx(PdfName key, PdfObject value) {
208 if (value == null)
209 return;
210 put(key, value);
211 }
212
213 /**
214 * Copies all of the mappings from the specified <CODE>PdfDictionary</CODE>
215 * to this <CODE>PdfDictionary</CODE>.
216 *
217 * These mappings will replace any mappings previously contained in this
218 * <CODE>PdfDictionary</CODE>.
219 *
220 * @param dic The <CODE>PdfDictionary</CODE> with the mappings to be
221 * copied over
222 */
223 public void putAll(PdfDictionary dic) {
224 hashMap.putAll(dic.hashMap);
225 }
226
227 /**
228 * Removes a <CODE>PdfObject</CODE> and its <VAR>key</VAR> from the
229 * <CODE>PdfDictionary</CODE>.
230 *
231 * @param key a <CODE>PdfName</CODE>
232 */
233 public void remove(PdfName key) {
234 hashMap.remove(key);
235 }
236
237 /**
238 * Returns the <CODE>PdfObject</CODE> associated to the specified
239 * <VAR>key</VAR>.
240 *
241 * @param key a <CODE>PdfName</CODE>
242 * @return the </CODE>PdfObject</CODE> previously associated to the
243 * <VAR>key</VAR>
244 */
245 public PdfObject get(PdfName key) {
246 return (PdfObject) hashMap.get(key);
247 }
248
249 /**
250 * Returns the <CODE>PdfObject</CODE> associated to the specified
251 * <VAR>key</VAR>, resolving a possible indirect reference to a direct
252 * object.
253 *
254 * This method will never return a <CODE>PdfIndirectReference</CODE>
255 * object.
256 *
257 * @param key A key for the <CODE>PdfObject</CODE> to be returned
258 * @return A direct <CODE>PdfObject</CODE> or <CODE>null</CODE>
259 */
260 public PdfObject getDirectObject(PdfName key) {
261 return PdfReader.getPdfObject(get(key));
262 }
263
264 /**
265 * Get all keys that are set.
266 *
267 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
268 */
269 public Set getKeys() {
270 return hashMap.keySet();
271 }
272
273 /**
274 * Returns the number of <VAR>key</VAR>-<VAR>value</VAR> mappings in this
275 * <CODE>PdfDictionary</CODE>.
276 *
277 * @return the number of <VAR>key</VAR>-<VAR>value</VAR> mappings in this
278 * <CODE>PdfDictionary</CODE>.
279 */
280 public int size() {
281 return hashMap.size();
282 }
283
284 /**
285 * Returns <CODE>true</CODE> if this <CODE>PdfDictionary</CODE> contains a
286 * mapping for the specified <VAR>key</VAR>.
287 *
288 * @return <CODE>true</CODE> if the key is set, otherwise <CODE>false</CODE>.
289 */
290 public boolean contains(PdfName key) {
291 return hashMap.containsKey(key);
292 }
293
294 // DICTIONARY TYPE METHODS
295
296 /**
297 * Checks if a <CODE>Dictionary</CODE> is of the type FONT.
298 *
299 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
300 */
301 public boolean isFont() {
302 return FONT.equals(dictionaryType);
303 }
304
305 /**
306 * Checks if a <CODE>Dictionary</CODE> is of the type PAGE.
307 *
308 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
309 */
310 public boolean isPage() {
311 return PAGE.equals(dictionaryType);
312 }
313
314 /**
315 * Checks if a <CODE>Dictionary</CODE> is of the type PAGES.
316 *
317 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
318 */
319 public boolean isPages() {
320 return PAGES.equals(dictionaryType);
321 }
322
323 /**
324 * Checks if a <CODE>Dictionary</CODE> is of the type CATALOG.
325 *
326 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
327 */
328 public boolean isCatalog() {
329 return CATALOG.equals(dictionaryType);
330 }
331
332 /**
333 * Checks if a <CODE>Dictionary</CODE> is of the type OUTLINES.
334 *
335 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>.
336 */
337 public boolean isOutlineTree() {
338 return OUTLINES.equals(dictionaryType);
339 }
340
341 // OTHER METHODS
342
343 public void merge(PdfDictionary other) {
344 hashMap.putAll(other.hashMap);
345 }
346
347 public void mergeDifferent(PdfDictionary other) {
348 for (Iterator i = other.hashMap.keySet().iterator(); i.hasNext();) {
349 Object key = i.next();
350 if (!hashMap.containsKey(key))
351 hashMap.put(key, other.hashMap.get(key));
352 }
353 }
354
355 // DOWNCASTING GETTERS
356 // @author Mark A Storer (2/17/06)
357
358 /**
359 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfDictionary</CODE>,
360 * resolving indirect references.
361 *
362 * The object associated with the <CODE>PdfName</CODE> given is retrieved
363 * and resolved to a direct object.
364 * If it is a <CODE>PdfDictionary</CODE>, it is cast down and returned as
365 * such. Otherwise <CODE>null</CODE> is returned.
366 *
367 * @param key A <CODE>PdfName</CODE>
368 * @return the associated <CODE>PdfDictionary</CODE> object,
369 * or <CODE>null</CODE>
370 */
371 public PdfDictionary getAsDict(PdfName key) {
372 PdfDictionary dict = null;
373 PdfObject orig = getDirectObject(key);
374 if (orig != null && orig.isDictionary())
375 dict = (PdfDictionary) orig;
376 return dict;
377 }
378
379 /**
380 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfArray</CODE>,
381 * resolving indirect references.
382 *
383 * The object associated with the <CODE>PdfName</CODE> given is retrieved
384 * and resolved to a direct object.
385 * If it is a <CODE>PdfArray</CODE>, it is cast down and returned as such.
386 * Otherwise <CODE>null</CODE> is returned.
387 *
388 * @param key A <CODE>PdfName</CODE>
389 * @return the associated <CODE>PdfArray</CODE> object,
390 * or <CODE>null</CODE>
391 */
392 public PdfArray getAsArray(PdfName key) {
393 PdfArray array = null;
394 PdfObject orig = getDirectObject(key);
395 if (orig != null && orig.isArray())
396 array = (PdfArray) orig;
397 return array;
398 }
399
400 /**
401 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfStream</CODE>,
402 * resolving indirect references.
403 *
404 * The object associated with the <CODE>PdfName</CODE> given is retrieved
405 * and resolved to a direct object.
406 * If it is a <CODE>PdfStream</CODE>, it is cast down and returned as such.
407 * Otherwise <CODE>null</CODE> is returned.
408 *
409 * @param key A <CODE>PdfName</CODE>
410 * @return the associated <CODE>PdfStream</CODE> object,
411 * or <CODE>null</CODE>
412 */
413 public PdfStream getAsStream(PdfName key) {
414 PdfStream stream = null;
415 PdfObject orig = getDirectObject(key);
416 if (orig != null && orig.isStream())
417 stream = (PdfStream) orig;
418 return stream;
419 }
420
421 /**
422 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfString</CODE>,
423 * resolving indirect references.
424 *
425 * The object associated with the <CODE>PdfName</CODE> given is retrieved
426 * and resolved to a direct object.
427 * If it is a <CODE>PdfString</CODE>, it is cast down and returned as such.
428 * Otherwise <CODE>null</CODE> is returned.
429 *
430 * @param key A <CODE>PdfName</CODE>
431 * @return the associated <CODE>PdfString</CODE> object,
432 * or <CODE>null</CODE>
433 */
434 public PdfString getAsString(PdfName key) {
435 PdfString string = null;
436 PdfObject orig = getDirectObject(key);
437 if (orig != null && orig.isString())
438 string = (PdfString) orig;
439 return string;
440 }
441
442 /**
443 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfNumber</CODE>,
444 * resolving indirect references.
445 *
446 * The object associated with the <CODE>PdfName</CODE> given is retrieved
447 * and resolved to a direct object.
448 * If it is a <CODE>PdfNumber</CODE>, it is cast down and returned as such.
449 * Otherwise <CODE>null</CODE> is returned.
450 *
451 * @param key A <CODE>PdfName</CODE>
452 * @return the associated <CODE>PdfNumber</CODE> object,
453 * or <CODE>null</CODE>
454 */
455 public PdfNumber getAsNumber(PdfName key) {
456 PdfNumber number = null;
457 PdfObject orig = getDirectObject(key);
458 if (orig != null && orig.isNumber())
459 number = (PdfNumber) orig;
460 return number;
461 }
462
463 /**
464 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfName</CODE>,
465 * resolving indirect references.
466 *
467 * The object associated with the <CODE>PdfName</CODE> given is retrieved
468 * and resolved to a direct object.
469 * If it is a <CODE>PdfName</CODE>, it is cast down and returned as such.
470 * Otherwise <CODE>null</CODE> is returned.
471 *
472 * @param key A <CODE>PdfName</CODE>
473 * @return the associated <CODE>PdfName</CODE> object,
474 * or <CODE>null</CODE>
475 */
476 public PdfName getAsName(PdfName key) {
477 PdfName name = null;
478 PdfObject orig = getDirectObject(key);
479 if (orig != null && orig.isName())
480 name = (PdfName) orig;
481 return name;
482 }
483
484 /**
485 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfBoolean</CODE>,
486 * resolving indirect references.
487 *
488 * The object associated with the <CODE>PdfName</CODE> given is retrieved
489 * and resolved to a direct object.
490 * If it is a <CODE>PdfBoolean</CODE>, it is cast down and returned as such.
491 * Otherwise <CODE>null</CODE> is returned.
492 *
493 * @param key A <CODE>PdfName</CODE>
494 * @return the associated <CODE>PdfBoolean</CODE> object,
495 * or <CODE>null</CODE>
496 */
497 public PdfBoolean getAsBoolean(PdfName key) {
498 PdfBoolean bool = null;
499 PdfObject orig = getDirectObject(key);
500 if (orig != null && orig.isBoolean())
501 bool = (PdfBoolean)orig;
502 return bool;
503 }
504
505 /**
506 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfIndirectReference</CODE>.
507 *
508 * The object associated with the <CODE>PdfName</CODE> given is retrieved
509 * If it is a <CODE>PdfIndirectReference</CODE>, it is cast down and returned
510 * as such. Otherwise <CODE>null</CODE> is returned.
511 *
512 * @param key A <CODE>PdfName</CODE>
513 * @return the associated <CODE>PdfIndirectReference</CODE> object,
514 * or <CODE>null</CODE>
515 */
516 public PdfIndirectReference getAsIndirectObject(PdfName key) {
517 PdfIndirectReference ref = null;
518 PdfObject orig = get(key); // not getDirect this time.
519 if (orig != null && orig.isIndirect())
520 ref = (PdfIndirectReference) orig;
521 return ref;
522 }
523 }