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 }