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