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