001/* 002 * $Id: PdfDictionary.java 4806 2011-04-13 09:20:24Z redlab_b $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.IOException; 047import java.io.OutputStream; 048import java.util.HashMap; 049import java.util.Map.Entry; 050import java.util.Set; 051 052/** 053 * <CODE>PdfDictionary</CODE> is the Pdf dictionary object. 054 * <P> 055 * A dictionary is an associative table containing pairs of objects. 056 * The first element of each pair is called the <I>key</I> and the second 057 * element is called the <I>value</I>. 058 * Unlike dictionaries in the PostScript language, a key must be a 059 * <CODE>PdfName</CODE>. 060 * A value can be any kind of <CODE>PdfObject</CODE>, including a dictionary. 061 * A dictionary is generally used to collect and tie together the attributes 062 * of a complex object, with each key-value pair specifying the name and value 063 * of an attribute.<BR> 064 * A dictionary is represented by two left angle brackets (<<), followed by a 065 * sequence of key-value pairs, followed by two right angle brackets (>>).<BR> 066 * This object is described in the 'Portable Document Format Reference Manual 067 * version 1.7' section 3.2.6 (page 59-60). 068 * <P> 069 * 070 * @see PdfObject 071 * @see PdfName 072 * @see BadPdfFormatException 073 */ 074public class PdfDictionary extends PdfObject { 075 076 // CONSTANTS 077 078 /** This is a possible type of dictionary */ 079 public static final PdfName FONT = PdfName.FONT; 080 081 /** This is a possible type of dictionary */ 082 public static final PdfName OUTLINES = PdfName.OUTLINES; 083 084 /** This is a possible type of dictionary */ 085 public static final PdfName PAGE = PdfName.PAGE; 086 087 /** This is a possible type of dictionary */ 088 public static final PdfName PAGES = PdfName.PAGES; 089 090 /** This is a possible type of dictionary */ 091 public static final PdfName CATALOG = PdfName.CATALOG; 092 093 // CLASS VARIABLES 094 095 /** This is the type of this dictionary */ 096 private PdfName dictionaryType = null; 097 098 /** This is the hashmap that contains all the values and keys of the dictionary */ 099 protected HashMap<PdfName, PdfObject> hashMap; 100 101 // CONSTRUCTORS 102 103 /** 104 * Constructs an empty <CODE>PdfDictionary</CODE>-object. 105 */ 106 public PdfDictionary() { 107 super(DICTIONARY); 108 hashMap = new HashMap<PdfName, PdfObject>(); 109 } 110 111 /** 112 * Constructs a <CODE>PdfDictionary</CODE>-object of a certain type. 113 * 114 * @param type a <CODE>PdfName</CODE> 115 */ 116 public PdfDictionary(final PdfName type) { 117 this(); 118 dictionaryType = type; 119 put(PdfName.TYPE, dictionaryType); 120 } 121 122 // METHODS OVERRIDING SOME PDFOBJECT METHODS 123 124 /** 125 * Writes the PDF representation of this <CODE>PdfDictionary</CODE> as an 126 * array of <CODE>byte</CODE> to the given <CODE>OutputStream</CODE>. 127 * 128 * @param writer for backwards compatibility 129 * @param os the <CODE>OutputStream</CODE> to write the bytes to. 130 * @throws IOException 131 */ 132 @Override 133 public void toPdf(final PdfWriter writer, final OutputStream os) throws IOException { 134 os.write('<'); 135 os.write('<'); 136 // loop over all the object-pairs in the HashMap 137 PdfObject value; 138 int type = 0; 139 for (Entry<PdfName, PdfObject> e: hashMap.entrySet()) { 140 e.getKey().toPdf(writer, os); 141 value = e.getValue(); 142 type = value.type(); 143 if (type != PdfObject.ARRAY && type != PdfObject.DICTIONARY && type != PdfObject.NAME && type != PdfObject.STRING) 144 os.write(' '); 145 value.toPdf(writer, os); 146 } 147 os.write('>'); 148 os.write('>'); 149 } 150 151 /** 152 * Returns a string representation of this <CODE>PdfDictionary</CODE>. 153 * 154 * The string doesn't contain any of the content of this dictionary. 155 * Rather the string "dictionary" is returned, possibly followed by the 156 * type of this <CODE>PdfDictionary</CODE>, if set. 157 * 158 * @return the string representation of this <CODE>PdfDictionary</CODE> 159 * @see com.itextpdf.text.pdf.PdfObject#toString() 160 */ 161 @Override 162 public String toString() { 163 if (get(PdfName.TYPE) == null) 164 return "Dictionary"; 165 return "Dictionary of type: " + get(PdfName.TYPE); 166 } 167 168 // DICTIONARY CONTENT METHODS 169 170 /** 171 * Associates the specified <CODE>PdfObject</CODE> as <VAR>value</VAR> with 172 * the specified <CODE>PdfName</CODE> as <VAR>key</VAR> in this map. 173 * 174 * If the map previously contained a mapping for this <VAR>key</VAR>, the 175 * old <VAR>value</VAR> is replaced. If the <VAR>value</VAR> is 176 * <CODE>null</CODE> or <CODE>PdfNull</CODE> the key is deleted. 177 * 178 * @param key a <CODE>PdfName</CODE> 179 * @param object the <CODE>PdfObject</CODE> to be associated with the 180 * <VAR>key</VAR> 181 */ 182 public void put(final PdfName key, final PdfObject object) { 183 if (object == null || object.isNull()) 184 hashMap.remove(key); 185 else 186 hashMap.put(key, object); 187 } 188 189 /** 190 * Associates the specified <CODE>PdfObject</CODE> as value to the 191 * specified <CODE>PdfName</CODE> as key in this map. 192 * 193 * If the <VAR>value</VAR> is a <CODE>PdfNull</CODE>, it is treated just as 194 * any other <CODE>PdfObject</CODE>. If the <VAR>value</VAR> is 195 * <CODE>null</CODE> however nothing is done. 196 * 197 * @param key a <CODE>PdfName</CODE> 198 * @param value the <CODE>PdfObject</CODE> to be associated to the 199 * <VAR>key</VAR> 200 */ 201 public void putEx(final PdfName key, final PdfObject value) { 202 if (value == null) 203 return; 204 put(key, value); 205 } 206 207 /** 208 * Copies all of the mappings from the specified <CODE>PdfDictionary</CODE> 209 * to this <CODE>PdfDictionary</CODE>. 210 * 211 * These mappings will replace any mappings previously contained in this 212 * <CODE>PdfDictionary</CODE>. 213 * 214 * @param dic The <CODE>PdfDictionary</CODE> with the mappings to be 215 * copied over 216 */ 217 public void putAll(final PdfDictionary dic) { 218 hashMap.putAll(dic.hashMap); 219 } 220 221 /** 222 * Removes a <CODE>PdfObject</CODE> and its <VAR>key</VAR> from the 223 * <CODE>PdfDictionary</CODE>. 224 * 225 * @param key a <CODE>PdfName</CODE> 226 */ 227 public void remove(final PdfName key) { 228 hashMap.remove(key); 229 } 230 231 /** 232 * Removes all the <CODE>PdfObject</CODE>s and its <VAR>key</VAR>s from the 233 * <CODE>PdfDictionary</CODE>. 234 * @since 5.0.2 235 */ 236 public void clear() { 237 hashMap.clear(); 238 } 239 240 /** 241 * Returns the <CODE>PdfObject</CODE> associated to the specified 242 * <VAR>key</VAR>. 243 * 244 * @param key a <CODE>PdfName</CODE> 245 * @return the </CODE>PdfObject</CODE> previously associated to the 246 * <VAR>key</VAR> 247 */ 248 public PdfObject get(final PdfName key) { 249 return hashMap.get(key); 250 } 251 252 /** 253 * Returns the <CODE>PdfObject</CODE> associated to the specified 254 * <VAR>key</VAR>, resolving a possible indirect reference to a direct 255 * object. 256 * 257 * This method will never return a <CODE>PdfIndirectReference</CODE> 258 * object. 259 * 260 * @param key A key for the <CODE>PdfObject</CODE> to be returned 261 * @return A direct <CODE>PdfObject</CODE> or <CODE>null</CODE> 262 */ 263 public PdfObject getDirectObject(final PdfName key) { 264 return PdfReader.getPdfObject(get(key)); 265 } 266 267 /** 268 * Get all keys that are set. 269 * 270 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 271 */ 272 public Set<PdfName> getKeys() { 273 return hashMap.keySet(); 274 } 275 276 /** 277 * Returns the number of <VAR>key</VAR>-<VAR>value</VAR> mappings in this 278 * <CODE>PdfDictionary</CODE>. 279 * 280 * @return the number of <VAR>key</VAR>-<VAR>value</VAR> mappings in this 281 * <CODE>PdfDictionary</CODE>. 282 */ 283 public int size() { 284 return hashMap.size(); 285 } 286 287 /** 288 * Returns <CODE>true</CODE> if this <CODE>PdfDictionary</CODE> contains a 289 * mapping for the specified <VAR>key</VAR>. 290 * 291 * @return <CODE>true</CODE> if the key is set, otherwise <CODE>false</CODE>. 292 */ 293 public boolean contains(final PdfName key) { 294 return hashMap.containsKey(key); 295 } 296 297 // DICTIONARY TYPE METHODS 298 299 /** 300 * Checks if a <CODE>Dictionary</CODE> is of the type FONT. 301 * 302 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 303 */ 304 public boolean isFont() { 305 return FONT.equals(dictionaryType); 306 } 307 308 /** 309 * Checks if a <CODE>Dictionary</CODE> is of the type PAGE. 310 * 311 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 312 */ 313 public boolean isPage() { 314 return PAGE.equals(dictionaryType); 315 } 316 317 /** 318 * Checks if a <CODE>Dictionary</CODE> is of the type PAGES. 319 * 320 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 321 */ 322 public boolean isPages() { 323 return PAGES.equals(dictionaryType); 324 } 325 326 /** 327 * Checks if a <CODE>Dictionary</CODE> is of the type CATALOG. 328 * 329 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 330 */ 331 public boolean isCatalog() { 332 return CATALOG.equals(dictionaryType); 333 } 334 335 /** 336 * Checks if a <CODE>Dictionary</CODE> is of the type OUTLINES. 337 * 338 * @return <CODE>true</CODE> if it is, otherwise <CODE>false</CODE>. 339 */ 340 public boolean isOutlineTree() { 341 return OUTLINES.equals(dictionaryType); 342 } 343 344 // OTHER METHODS 345 346 public void merge(final PdfDictionary other) { 347 hashMap.putAll(other.hashMap); 348 } 349 350 public void mergeDifferent(final PdfDictionary other) { 351 for (PdfName key : other.hashMap.keySet()) { 352 if (!hashMap.containsKey(key)) 353 hashMap.put(key, other.hashMap.get(key)); 354 } 355 } 356 357 // DOWNCASTING GETTERS 358 // @author Mark A Storer (2/17/06) 359 360 /** 361 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfDictionary</CODE>, 362 * resolving indirect references. 363 * 364 * The object associated with the <CODE>PdfName</CODE> given is retrieved 365 * and resolved to a direct object. 366 * If it is a <CODE>PdfDictionary</CODE>, it is cast down and returned as 367 * such. Otherwise <CODE>null</CODE> is returned. 368 * 369 * @param key A <CODE>PdfName</CODE> 370 * @return the associated <CODE>PdfDictionary</CODE> object, 371 * or <CODE>null</CODE> 372 */ 373 public PdfDictionary getAsDict(final PdfName key) { 374 PdfDictionary dict = null; 375 PdfObject orig = getDirectObject(key); 376 if (orig != null && orig.isDictionary()) 377 dict = (PdfDictionary) orig; 378 return dict; 379 } 380 381 /** 382 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfArray</CODE>, 383 * resolving indirect references. 384 * 385 * The object associated with the <CODE>PdfName</CODE> given is retrieved 386 * and resolved to a direct object. 387 * If it is a <CODE>PdfArray</CODE>, it is cast down and returned as such. 388 * Otherwise <CODE>null</CODE> is returned. 389 * 390 * @param key A <CODE>PdfName</CODE> 391 * @return the associated <CODE>PdfArray</CODE> object, 392 * or <CODE>null</CODE> 393 */ 394 public PdfArray getAsArray(final PdfName key) { 395 PdfArray array = null; 396 PdfObject orig = getDirectObject(key); 397 if (orig != null && orig.isArray()) 398 array = (PdfArray) orig; 399 return array; 400 } 401 402 /** 403 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfStream</CODE>, 404 * resolving indirect references. 405 * 406 * The object associated with the <CODE>PdfName</CODE> given is retrieved 407 * and resolved to a direct object. 408 * If it is a <CODE>PdfStream</CODE>, it is cast down and returned as such. 409 * Otherwise <CODE>null</CODE> is returned. 410 * 411 * @param key A <CODE>PdfName</CODE> 412 * @return the associated <CODE>PdfStream</CODE> object, 413 * or <CODE>null</CODE> 414 */ 415 public PdfStream getAsStream(final PdfName key) { 416 PdfStream stream = null; 417 PdfObject orig = getDirectObject(key); 418 if (orig != null && orig.isStream()) 419 stream = (PdfStream) orig; 420 return stream; 421 } 422 423 /** 424 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfString</CODE>, 425 * resolving indirect references. 426 * 427 * The object associated with the <CODE>PdfName</CODE> given is retrieved 428 * and resolved to a direct object. 429 * If it is a <CODE>PdfString</CODE>, it is cast down and returned as such. 430 * Otherwise <CODE>null</CODE> is returned. 431 * 432 * @param key A <CODE>PdfName</CODE> 433 * @return the associated <CODE>PdfString</CODE> object, 434 * or <CODE>null</CODE> 435 */ 436 public PdfString getAsString(final PdfName key) { 437 PdfString string = null; 438 PdfObject orig = getDirectObject(key); 439 if (orig != null && orig.isString()) 440 string = (PdfString) orig; 441 return string; 442 } 443 444 /** 445 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfNumber</CODE>, 446 * resolving indirect references. 447 * 448 * The object associated with the <CODE>PdfName</CODE> given is retrieved 449 * and resolved to a direct object. 450 * If it is a <CODE>PdfNumber</CODE>, it is cast down and returned as such. 451 * Otherwise <CODE>null</CODE> is returned. 452 * 453 * @param key A <CODE>PdfName</CODE> 454 * @return the associated <CODE>PdfNumber</CODE> object, 455 * or <CODE>null</CODE> 456 */ 457 public PdfNumber getAsNumber(final PdfName key) { 458 PdfNumber number = null; 459 PdfObject orig = getDirectObject(key); 460 if (orig != null && orig.isNumber()) 461 number = (PdfNumber) orig; 462 return number; 463 } 464 465 /** 466 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfName</CODE>, 467 * resolving indirect references. 468 * 469 * The object associated with the <CODE>PdfName</CODE> given is retrieved 470 * and resolved to a direct object. 471 * If it is a <CODE>PdfName</CODE>, it is cast down and returned as such. 472 * Otherwise <CODE>null</CODE> is returned. 473 * 474 * @param key A <CODE>PdfName</CODE> 475 * @return the associated <CODE>PdfName</CODE> object, 476 * or <CODE>null</CODE> 477 */ 478 public PdfName getAsName(final PdfName key) { 479 PdfName name = null; 480 PdfObject orig = getDirectObject(key); 481 if (orig != null && orig.isName()) 482 name = (PdfName) orig; 483 return name; 484 } 485 486 /** 487 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfBoolean</CODE>, 488 * resolving indirect references. 489 * 490 * The object associated with the <CODE>PdfName</CODE> given is retrieved 491 * and resolved to a direct object. 492 * If it is a <CODE>PdfBoolean</CODE>, it is cast down and returned as such. 493 * Otherwise <CODE>null</CODE> is returned. 494 * 495 * @param key A <CODE>PdfName</CODE> 496 * @return the associated <CODE>PdfBoolean</CODE> object, 497 * or <CODE>null</CODE> 498 */ 499 public PdfBoolean getAsBoolean(final PdfName key) { 500 PdfBoolean bool = null; 501 PdfObject orig = getDirectObject(key); 502 if (orig != null && orig.isBoolean()) 503 bool = (PdfBoolean)orig; 504 return bool; 505 } 506 507 /** 508 * Returns a <CODE>PdfObject</CODE> as a <CODE>PdfIndirectReference</CODE>. 509 * 510 * The object associated with the <CODE>PdfName</CODE> given is retrieved 511 * If it is a <CODE>PdfIndirectReference</CODE>, it is cast down and returned 512 * as such. Otherwise <CODE>null</CODE> is returned. 513 * 514 * @param key A <CODE>PdfName</CODE> 515 * @return the associated <CODE>PdfIndirectReference</CODE> object, 516 * or <CODE>null</CODE> 517 */ 518 public PdfIndirectReference getAsIndirectObject(final PdfName key) { 519 PdfIndirectReference ref = null; 520 PdfObject orig = get(key); // not getDirect this time. 521 if (orig != null && orig.isIndirect()) 522 ref = (PdfIndirectReference) orig; 523 return ref; 524 } 525}