1 /***************************************************************************
2 * Copyright (C) 2006 by Dominik Seichter *
3 * domseichter@web.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Library General Public License as *
7 * published by the Free Software Foundation; either version 2 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Library General Public *
16 * License along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 * *
20 * In addition, as a special exception, the copyright holders give *
21 * permission to link the code of portions of this program with the *
22 * OpenSSL library under certain conditions as described in each *
23 * individual source file, and distribute linked combinations *
24 * including the two. *
25 * You must obey the GNU General Public License in all respects *
26 * for all of the code used other than OpenSSL. If you modify *
27 * file(s) with this exception, you may extend this exception to your *
28 * version of the file(s), but you are not obligated to do so. If you *
29 * do not wish to do so, delete this exception statement from your *
30 * version. If you delete this exception statement from all source *
31 * files in the program, then also delete it here. *
32 ***************************************************************************/
33
34 #ifndef _PDF_DICTIONARY_H_
35 #define _PDF_DICTIONARY_H_
36
37 #include "PdfDefines.h"
38 #include "PdfOwnedDataType.h"
39
40 #include "PdfName.h"
41 #include "PdfObject.h"
42
43 /**
44 * PODOFO_USE_UNORDERED_MAP
45 *
46 * If you set this define, PoDoFo
47 * will use std::tr1::unordered_map instead
48 * of std::map for PdfDictionary.
49 *
50 * Some benchmarking tests using callgrind have shown
51 * that unordered_map is a little faster for writing and AddKey
52 * but of course slower for GetKey and HasKey. As PdfDictionaries
53 * are usually very small the difference for GetKey and HasKey is
54 * not very large and should therefore be rarely noticeable.
55 *
56 * By default this define is not set and std::map will be used.
57 */
58 #ifdef PODOFO_USE_UNORDERED_MAP
59 #include <tr1/unordered_map>
60 #endif // PODOFO_USE_ORDERED_MAP
61
62 namespace PoDoFo {
63
64 #ifdef PODOFO_USE_UNORDERED_MAP
65 class PdfNameHash : public std::unary_function<PdfName, size_t>
66 {
67 public:
operator()68 size_t operator()( const PdfName& v ) const
69 {
70 std::tr1::hash<std::string> hasher;
71
72 return hasher( v.GetName() );
73 }
74 };
75
76 typedef std::tr1::unordered_map<PdfName,PdfObject*, PdfNameHash> TKeyMap;
77 #else
78 typedef std::map<PdfName,PdfObject*> TKeyMap;
79 #endif // PODOFO_USE_UNORDERED_MAP
80
81 typedef TKeyMap::iterator TIKeyMap;
82 typedef TKeyMap::const_iterator TCIKeyMap;
83
84 class PdfOutputDevice;
85
86 /** The PDF dictionary data type of PoDoFo (inherits from PdfDataType,
87 * the base class for such representations)
88 */
89 class PODOFO_API PdfDictionary : public PdfOwnedDataType {
90 public:
91 /** Create a new, empty dictionary
92 */
93 PdfDictionary();
94
95 /** Deep copy a dictionary
96 * \param rhs the PdfDictionary to copy
97 */
98 PdfDictionary( const PdfDictionary & rhs );
99
100 /** Destructor
101 */
102 virtual ~PdfDictionary();
103
104 /** Asignment operator.
105 * Asign another PdfDictionary to this dictionary. This is a deep copy;
106 * all elements of the source dictionary are duplicated.
107 *
108 * \param rhs the PdfDictionary to copy.
109 *
110 * \return this PdfDictionary
111 *
112 * This will set the dirty flag of this object.
113 * \see IsDirty
114 */
115 const PdfDictionary & operator=( const PdfDictionary & rhs );
116
117 /**
118 * Comparison operator. If this dictionary contains all the same keys
119 * as the other dictionary, and for each key the values compare equal,
120 * the dictionaries are considered equal.
121 */
122 bool operator==( const PdfDictionary& rhs ) const;
123
124 /**
125 * \see operator==
126 */
127 inline bool operator!=( const PdfDictionary& rhs ) const;
128
129 /** Removes all keys from the dictionary
130 */
131 void Clear();
132
133 /** Add a key to the dictionary. If an existing key of this name exists, its
134 * value is replaced and the old value object will be deleted. The passed
135 * object is copied.
136 *
137 * \param identifier the key is identified by this name in the dictionary
138 * \param rObject a variant object containing the data. The object is copied.
139 *
140 * This will set the dirty flag of this object.
141 * \see IsDirty
142 */
143 void AddKey( const PdfName & identifier, const PdfObject & rObject );
144
145 /** Add a key to the dictionary. If an existing key of this name exists,
146 * its value is replaced and the old value object will be deleted. The
147 * passed object is copied.
148 *
149 * This is an overloaded member function.
150 *
151 * \param identifier the key is identified by this name in the dictionary
152 * \param pObject pointer to a variant object containing the data. The object is copied.
153 *
154 * This will set the dirty flag of this object.
155 * \see IsDirty
156 */
157 void AddKey( const PdfName & identifier, const PdfObject* pObject );
158
159 /** Get the key's value out of the dictionary.
160 *
161 * The returned value is a pointer to the internal object in the dictionary
162 * so it MUST not be deleted.
163 *
164 * \param key look for the key named key in the dictionary
165 *
166 * \returns pointer to the found value, or 0 if the key was not found.
167 */
168 inline const PdfObject* GetKey( const PdfName & key ) const;
169
170 /** Get the key's value out of the dictionary. This is an overloaded member
171 * function.
172 *
173 * The returned value is a pointer to the internal object in the dictionary.
174 * It may be modified but is still owned by the dictionary so it MUST not
175 * be deleted.
176 *
177 * \param key look for the key named key in the dictionary
178 *
179 * \returns the found value, or 0 if the key was not found.
180 */
181 inline PdfObject* GetKey( const PdfName & key );
182
183 /** Get the keys value out of the dictionary
184 *
185 * Lookup in the indirect objects as well, if the shallow object was a reference.
186 * The returned value is a pointer to the internal object in the dictionary
187 * so it MUST not be deleted.
188 *
189 * \param key look for the key names pszKey in the dictionary
190 * \returns pointer to the found value or 0 if the key was not found.
191 */
192 inline const PdfObject* FindKey( const PdfName & key ) const;
193 inline PdfObject* FindKey( const PdfName & key );
194
195 /** Get the keys value out of the dictionary
196 *
197 * Lookup in the indirect objects as well, if the shallow object was a reference.
198 * Also lookup the parent objects, if /Parent key is found in the dictionary.
199 * The returned value is a pointer to the internal object in the dictionary
200 * so it MUST not be deleted.
201 *
202 * \param key look for the key names pszKey in the dictionary
203 * \returns pointer to the found value or 0 if the key was not found.
204 */
205 inline const PdfObject* FindKeyParent( const PdfName & key ) const;
206 inline PdfObject* FindKeyParent( const PdfName & key );
207
208 /** Get the key's value out of the dictionary.
209 *
210 * The returned value is a reference to the internal object in the dictionary
211 * so it MUST not be deleted. If the key is not found, this throws a PdfError
212 * exception with error code ePdfError_NoObject, instead of returning.
213 * This is intended to make code more readable by sparing (especially multiple)
214 * NULL checks.
215 *
216 * \param key look for the key named key in the dictionary
217 *
218 * \returns reference to the found value (never 0).
219 * \throws PdfError(ePdfError_NoObject).
220 */
221 inline const PdfObject& MustGetKey( const PdfName & key ) const;
222
223 pdf_int64 GetKeyAsLong( const PdfName & key, pdf_int64 lDefault = 0 ) const;
224
225 double GetKeyAsReal( const PdfName & key, double dDefault = 0.0 ) const;
226
227 bool GetKeyAsBool( const PdfName & key, bool bDefault = false ) const;
228
229 PdfName GetKeyAsName( const PdfName & key ) const;
230
231 /** Allows to check if a dictionary contains a certain key.
232 * \param key look for the key named key.Name() in the dictionary
233 *
234 * \returns true if the key is part of the dictionary, otherwise false.
235 */
236 bool HasKey( const PdfName & key ) const;
237
238 /** Remove a key from this dictionary. If the key does not exist, this
239 * function does nothing.
240 *
241 * \param identifier the name of the key to delete
242 *
243 * \returns true if the key was found in the object and was removed.
244 * If there was no key with this name, false is returned.
245 *
246 * This will set the dirty flag of this object.
247 * \see IsDirty
248 */
249 bool RemoveKey( const PdfName & identifier );
250
251 /** Write the complete dictionary to a file.
252 *
253 * \param pDevice write the object to this device
254 * \param eWriteMode additional options for writing this object
255 * \param pEncrypt an encryption object which is used to encrypt this object
256 * or NULL to not encrypt this object
257 */
258 inline void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const;
259
260 /** Write the complete dictionary to a file.
261 *
262 * \param pDevice write the object to this device
263 * \param eWriteMode additional options for writing this object
264 * \param pEncrypt an encryption object which is used to encrypt this object
265 * or NULL to not encrypt this object
266 * \param keyStop if not KeyNull and a key == keyStop is found
267 * writing will stop right before this key!
268 */
269 void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode,
270 const PdfEncrypt* pEncrypt, const PdfName & keyStop = PdfName::KeyNull ) const;
271
272 /**
273 * \returns the size of the internal map
274 */
275 inline size_t GetSize() const;
276
277 /** Get access to the internal map of keys.
278 *
279 * \returns all keys of this dictionary
280 */
281 inline const TKeyMap & GetKeys() const;
282
283 /** Get access to the internal map of keys.
284 * \returns all keys of this dictionary
285 */
286 inline TKeyMap & GetKeys();
287
288 /** The dirty flag is set if this variant
289 * has been modified after construction.
290 *
291 * Usually the dirty flag is also set
292 * if you call any non-const member function
293 * as we cannot determine if you actually changed
294 * something or not.
295 *
296 * \returns true if the value is dirty and has been
297 * modified since construction
298 */
299 virtual bool IsDirty() const;
300
301 /** Sets the dirty flag of this PdfVariant
302 *
303 * \param bDirty true if this PdfVariant has been
304 * modified from the outside
305 *
306 * \see IsDirty
307 */
308 virtual void SetDirty( bool bDirty );
309
310 public:
311 TCIKeyMap begin() const;
312 TCIKeyMap end() const;
313
314 protected:
315 void SetOwner( PdfObject* pOwner );
316
317 private:
318 PdfObject * getKey(const PdfName & key) const;
319 PdfObject * findKey(const PdfName & key) const;
320 PdfObject * findKeyParent(const PdfName & key) const;
321
322 private:
323 TKeyMap m_mapKeys;
324
325 bool m_bDirty; ///< Indicates if this object was modified after construction
326 };
327
328 typedef std::vector<PdfDictionary*> TVecDictionaries;
329 typedef TVecDictionaries::iterator TIVecDictionaries;
330 typedef TVecDictionaries::const_iterator TCIVecDictionaries;
331
332 // -----------------------------------------------------
333 //
334 // -----------------------------------------------------
GetKey(const PdfName & key)335 inline const PdfObject * PdfDictionary::GetKey( const PdfName &key ) const
336 {
337 return getKey(key);
338 }
339
340 // -----------------------------------------------------
341 //
342 // -----------------------------------------------------
GetKey(const PdfName & key)343 inline PdfObject * PdfDictionary::GetKey( const PdfName &key )
344 {
345 return getKey(key);
346 }
347
348 // -----------------------------------------------------
349 //
350 // -----------------------------------------------------
FindKey(const PdfName & key)351 inline const PdfObject * PdfDictionary::FindKey( const PdfName &key ) const
352 {
353 return findKey(key);
354 }
355
356 // -----------------------------------------------------
357 //
358 // -----------------------------------------------------
FindKey(const PdfName & key)359 inline PdfObject * PdfDictionary::FindKey( const PdfName &key )
360 {
361 return findKey(key);
362 }
363
364 // -----------------------------------------------------
365 //
366 // -----------------------------------------------------
FindKeyParent(const PdfName & key)367 inline const PdfObject* PdfDictionary::FindKeyParent( const PdfName &key ) const
368 {
369 return findKeyParent(key);
370 }
371
372 // -----------------------------------------------------
373 //
374 // -----------------------------------------------------
FindKeyParent(const PdfName & key)375 inline PdfObject* PdfDictionary::FindKeyParent( const PdfName &key )
376 {
377 return findKeyParent(key);
378 }
379
380 // -----------------------------------------------------
381 //
382 // -----------------------------------------------------
GetSize()383 size_t PdfDictionary::GetSize() const
384 {
385 return m_mapKeys.size();
386 }
387
388 // -----------------------------------------------------
389 //
390 // -----------------------------------------------------
GetKeys()391 const TKeyMap & PdfDictionary::GetKeys() const
392 {
393 return m_mapKeys;
394 }
395
396 // -----------------------------------------------------
397 //
398 // -----------------------------------------------------
GetKeys()399 TKeyMap & PdfDictionary::GetKeys()
400 {
401 return m_mapKeys;
402 }
403
404 // -----------------------------------------------------
405 //
406 // -----------------------------------------------------
MustGetKey(const PdfName & key)407 const PdfObject& PdfDictionary::MustGetKey( const PdfName & key ) const
408 {
409 const PdfObject* obj = GetKey( key );
410 if (!obj)
411 PODOFO_RAISE_ERROR( ePdfError_NoObject );
412 return *obj;
413 }
414
415 // -----------------------------------------------------
416 //
417 // -----------------------------------------------------
Write(PdfOutputDevice * pDevice,EPdfWriteMode eWriteMode,const PdfEncrypt * pEncrypt)418 void PdfDictionary::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt ) const
419 {
420 this->Write( pDevice, eWriteMode, pEncrypt, PdfName::KeyNull );
421 }
422
423 // -----------------------------------------------------
424 //
425 // -----------------------------------------------------
426 bool PdfDictionary::operator!=( const PdfDictionary& rhs ) const
427 {
428 return !(*this == rhs);
429 }
430
431 };
432
433 #endif // _PDF_DICTIONARY_H_
434