1 /***************************************************************************
2  *   Copyright (C) 2005 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 #include "PdfObject.h"
35 
36 #include "PdfArray.h"
37 #include "PdfDictionary.h"
38 #include "PdfEncrypt.h"
39 #include "PdfFileStream.h"
40 #include "PdfOutputDevice.h"
41 #include "PdfStream.h"
42 #include "PdfVariant.h"
43 #include "PdfDefinesPrivate.h"
44 
45 #include <sstream>
46 #include <fstream>
47 
48 #include <string.h>
49 
50 using namespace std;
51 
52 namespace PoDoFo {
53 
PdfObject()54 PdfObject::PdfObject()
55     : PdfVariant( PdfDictionary() )
56 {
57     InitPdfObject();
58 }
59 
PdfObject(const PdfReference & rRef,const char * pszType)60 PdfObject::PdfObject( const PdfReference & rRef, const char* pszType )
61     : PdfVariant( PdfDictionary() ), m_reference( rRef )
62 {
63     InitPdfObject();
64 
65     if( pszType )
66         this->GetDictionary().AddKey( PdfName::KeyType, PdfName( pszType ) );
67 }
68 
PdfObject(const PdfReference & rRef,const PdfVariant & rVariant)69 PdfObject::PdfObject( const PdfReference & rRef, const PdfVariant & rVariant )
70     : PdfVariant( rVariant ), m_reference( rRef )
71 {
72     InitPdfObject();
73 }
74 
PdfObject(const PdfVariant & var)75 PdfObject::PdfObject( const PdfVariant & var )
76     : PdfVariant( var )
77 {
78     InitPdfObject();
79 }
80 
PdfObject(bool b)81 PdfObject::PdfObject( bool b )
82     : PdfVariant( b )
83 {
84     InitPdfObject();
85 }
86 
PdfObject(pdf_int64 l)87 PdfObject::PdfObject( pdf_int64 l )
88     : PdfVariant( l )
89 {
90     InitPdfObject();
91 }
92 
PdfObject(double d)93 PdfObject::PdfObject( double d )
94     : PdfVariant( d )
95 {
96     InitPdfObject();
97 }
98 
PdfObject(const PdfString & rsString)99 PdfObject::PdfObject( const PdfString & rsString )
100     : PdfVariant( rsString )
101 {
102     InitPdfObject();
103 }
104 
PdfObject(const PdfName & rName)105 PdfObject::PdfObject( const PdfName & rName )
106     : PdfVariant( rName )
107 {
108     InitPdfObject();
109 }
110 
PdfObject(const PdfReference & rRef)111 PdfObject::PdfObject( const PdfReference & rRef )
112     : PdfVariant( rRef )
113 {
114     InitPdfObject();
115 }
116 
PdfObject(const PdfArray & tList)117 PdfObject::PdfObject( const PdfArray & tList )
118     : PdfVariant( tList )
119 {
120     InitPdfObject();
121 }
122 
PdfObject(const PdfDictionary & rDict)123 PdfObject::PdfObject( const PdfDictionary & rDict )
124     : PdfVariant( rDict )
125 {
126     InitPdfObject();
127 }
128 
129 // NOTE: Don't copy owner. Copied objects must be always detached.
130 // Ownership will be set automatically elsewhere
PdfObject(const PdfObject & rhs)131 PdfObject::PdfObject( const PdfObject & rhs )
132     : PdfVariant( rhs ), m_reference( rhs.m_reference )
133 {
134     InitPdfObject();
135 
136     // DS: If you change this code, also change the assignment operator.
137     //     As the copy constructor is called very often,
138     //     it contains a copy of parts of the assignment code to be faster.
139     const_cast<PdfObject*>(&rhs)->DelayedStreamLoad();
140     m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone();
141 
142     // FIXME:
143     // Copying stream is currently broken:
144     // 1) PdfVecObjects::CreateStream( const PdfStream & ) is broken as it just returns NULL
145     // 2) Stream should be copyable also when m_pOwner is NULL (which is the case for copy constructor)
146     //if( rhs.m_pStream && m_pOwner )
147     //    m_pStream = m_pOwner->CreateStream( *(rhs.m_pStream) );
148 
149 #if defined(PODOFO_EXTRA_CHECKS)
150     // Must've been demand loaded or already done
151     PODOFO_ASSERT( DelayedLoadDone() );
152     PODOFO_ASSERT( DelayedStreamLoadDone() );
153 #endif
154 }
155 
~PdfObject()156 PdfObject::~PdfObject()
157 {
158     delete m_pStream;
159     m_pStream = NULL;
160 }
161 
SetOwner(PdfVecObjects * pVecObjects)162 void PdfObject::SetOwner( PdfVecObjects* pVecObjects )
163 {
164     PODOFO_ASSERT( pVecObjects != NULL );
165     if ( m_pOwner == pVecObjects )
166     {
167         // The inner owner for variant data objects is guaranteed to be same
168         return;
169     }
170 
171     m_pOwner = pVecObjects;
172     if ( DelayedLoadDone() )
173         SetVariantOwner( GetDataType() );
174 }
175 
AfterDelayedLoad(EPdfDataType eDataType)176 void PdfObject::AfterDelayedLoad( EPdfDataType eDataType )
177 {
178     SetVariantOwner( eDataType );
179 }
180 
SetVariantOwner(EPdfDataType eDataType)181 void PdfObject::SetVariantOwner( EPdfDataType eDataType )
182 {
183     switch ( eDataType )
184     {
185         case ePdfDataType_Dictionary:
186             static_cast<PdfOwnedDataType &>( GetDictionary_NoDL() ).SetOwner( this );
187             break;
188         case ePdfDataType_Array:
189             static_cast<PdfOwnedDataType &>( GetArray_NoDL() ).SetOwner( this );
190             break;
191         default:
192             break;
193     }
194 }
195 
InitPdfObject()196 void PdfObject::InitPdfObject()
197 {
198     m_pStream                 = NULL;
199     m_pOwner                  = NULL;
200     m_bDelayedStreamLoadDone  = true;
201     SetVariantOwner( GetDataType() );
202 
203 #if defined(PODOFO_EXTRA_CHECKS)
204     m_bDelayedStreamLoadInProgress = false;
205 #endif
206 }
207 
WriteObject(PdfOutputDevice * pDevice,EPdfWriteMode eWriteMode,PdfEncrypt * pEncrypt,const PdfName & keyStop) const208 void PdfObject::WriteObject( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode,
209                              PdfEncrypt* pEncrypt, const PdfName & keyStop ) const
210 {
211     DelayedStreamLoad();
212 
213     if( !pDevice )
214     {
215         PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
216     }
217 
218     if( m_reference.IsIndirect() )
219     {
220         if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean )
221         {
222             pDevice->Print( "%i %i obj\n", m_reference.ObjectNumber(), m_reference.GenerationNumber() );
223         }
224         else
225         {
226             pDevice->Print( "%i %i obj", m_reference.ObjectNumber(), m_reference.GenerationNumber() );
227         }
228     }
229 
230     if( pEncrypt )
231     {
232         pEncrypt->SetCurrentReference( m_reference );
233     }
234 
235     if( pEncrypt && m_pStream )
236     {
237         // Set length if it is a key
238         PdfFileStream* pFileStream = dynamic_cast<PdfFileStream*>(m_pStream);
239         if( !pFileStream )
240         {
241             // PdfFileStream handles encryption internally
242             pdf_long lLength = pEncrypt->CalculateStreamLength(m_pStream->GetLength());
243             PdfVariant varLength = static_cast<pdf_int64>(lLength);
244             *(const_cast<PdfObject*>(this)->GetIndirectKey( PdfName::KeyLength )) = varLength;
245         }
246     }
247 
248     this->Write( pDevice, eWriteMode, pEncrypt, keyStop );
249     pDevice->Print( "\n" );
250 
251     if( m_pStream )
252     {
253         m_pStream->Write( pDevice, pEncrypt );
254     }
255 
256     if( m_reference.IsIndirect() )
257     {
258         pDevice->Print( "endobj\n" );
259     }
260 }
261 
GetIndirectKey(const PdfName & key) const262 PdfObject* PdfObject::GetIndirectKey( const PdfName & key ) const
263 {
264     if ( !this->IsDictionary() )
265         return NULL;
266 
267     // DominikS: TODO Remove const on GetIndirectKey
268     return const_cast<PdfObject*>( this->GetDictionary().FindKey( key ) );
269 }
270 
GetIndirectKeyAsLong(const PdfName & key,pdf_int64 lDefault) const271 pdf_int64 PdfObject::GetIndirectKeyAsLong( const PdfName & key, pdf_int64 lDefault ) const
272 {
273     const PdfObject* pObject = GetIndirectKey( key );
274 
275     if( pObject && pObject->GetDataType() == ePdfDataType_Number )
276     {
277         return pObject->GetNumber();
278     }
279 
280     return lDefault;
281 }
282 
GetIndirectKeyAsReal(const PdfName & key,double dDefault) const283 double PdfObject::GetIndirectKeyAsReal( const PdfName & key, double dDefault ) const
284 {
285     const PdfObject* pObject = GetIndirectKey( key );
286 
287     if( pObject && (
288         pObject->GetDataType() == ePdfDataType_Real ||
289         pObject->GetDataType() == ePdfDataType_Number))
290     {
291         return pObject->GetReal();
292     }
293 
294     return dDefault;
295 }
296 
GetIndirectKeyAsBool(const PdfName & key,bool bDefault) const297 bool PdfObject::GetIndirectKeyAsBool( const PdfName & key, bool bDefault ) const
298 {
299     const PdfObject* pObject = GetIndirectKey( key );
300 
301     if( pObject && pObject->GetDataType() == ePdfDataType_Bool )
302     {
303         return pObject->GetBool();
304     }
305 
306     return bDefault;
307 }
308 
GetIndirectKeyAsName(const PdfName & key) const309 PdfName PdfObject::GetIndirectKeyAsName( const PdfName & key ) const
310 {
311     const PdfObject* pObject = GetIndirectKey( key );
312 
313     if( pObject && pObject->GetDataType() == ePdfDataType_Name )
314     {
315         return pObject->GetName();
316     }
317 
318     return PdfName(""); // return an empty name
319 }
320 
GetObjectLength(EPdfWriteMode eWriteMode)321 pdf_long PdfObject::GetObjectLength( EPdfWriteMode eWriteMode )
322 {
323     PdfOutputDevice device;
324 
325     this->WriteObject( &device, eWriteMode, NULL  );
326 
327     return device.GetLength();
328 }
329 
GetStream()330 PdfStream* PdfObject::GetStream()
331 {
332     DelayedStreamLoad();
333     return GetStream_NoDL();
334 }
335 
GetStream_NoDL()336 PdfStream* PdfObject::GetStream_NoDL()
337 {
338     if( !m_pStream )
339     {
340         if ( GetDataType() != ePdfDataType_Dictionary )
341         {
342             PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Tried to get stream of non-dictionary object");
343 	    }
344         if ( !m_reference.IsIndirect() )
345 		{
346             PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Tried to get stream of non-indirect PdfObject");
347 		}
348         if( !m_pOwner )
349         {
350             PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Tried to create stream on PdfObject lacking owning document/PdfVecObjects" );
351         }
352 
353         m_pStream = m_pOwner->CreateStream( this );
354     }
355 
356     SetDirty( true );
357     return m_pStream;
358 }
359 
GetStream() const360 const PdfStream* PdfObject::GetStream() const
361 {
362     DelayedStreamLoad();
363 
364     return m_pStream;
365 }
366 
FlateCompressStream()367 void PdfObject::FlateCompressStream()
368 {
369     // TODO: If the stream isn't already in memory, defer loading and compression until first read of the stream to save some memory.
370     DelayedStreamLoad();
371 
372     /*
373     if( m_pStream )
374         m_pStream->FlateCompress();
375     */
376 }
377 
operator =(const PdfObject & rhs)378 const PdfObject & PdfObject::operator=( const PdfObject & rhs )
379 {
380     if( &rhs == this)
381         return *this;
382 
383     // DS: If you change this code, also change the copy constructor.
384     //     As the copy constructor is called very often,
385     //     it contains a copy of parts of this code to be faster.
386 
387     delete m_pStream;
388     m_pStream = NULL;
389 
390     const_cast<PdfObject*>(&rhs)->DelayedStreamLoad();
391 
392     // NOTE: Don't copy owner. Objects being assigned always keep current ownership
393     PdfVariant::operator=(rhs);
394     m_reference     = rhs.m_reference;
395     m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone();
396     SetVariantOwner( GetDataType() );
397 
398     // FIXME:
399     // Copying stream is currently broken:
400     // 1) PdfVecObjects::CreateStream( const PdfStream & ) is broken as it just returns NULL
401     // 2) Stream should be copyable also when m_pOwner is NULL
402     //if( rhs.m_pStream )
403     //    m_pStream = m_pOwner->CreateStream( *(rhs.m_pStream) );
404 
405 #if defined(PODOFO_EXTRA_CHECKS)
406     // Must've been demand loaded or already done
407     PODOFO_ASSERT( DelayedLoadDone() );
408     PODOFO_ASSERT( DelayedStreamLoadDone() );
409 #endif
410 
411     return *this;
412 }
413 
GetByteOffset(const char * pszKey,EPdfWriteMode eWriteMode)414 pdf_long PdfObject::GetByteOffset( const char* pszKey, EPdfWriteMode eWriteMode )
415 {
416     PdfOutputDevice device;
417 
418     if( !pszKey )
419     {
420         PODOFO_RAISE_ERROR( ePdfError_InvalidHandle );
421     }
422 
423     if( !this->GetDictionary().HasKey( pszKey ) )
424     {
425         PODOFO_RAISE_ERROR( ePdfError_InvalidKey );
426     }
427 
428     this->Write( &device, eWriteMode, NULL, pszKey );
429 
430     return device.GetLength();
431 }
432 
433 };
434