1 /***************************************************************************
2 * Copyright (C) 2007 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 "PdfImmediateWriter.h"
35
36 #include "PdfFileStream.h"
37 #include "PdfMemStream.h"
38 #include "PdfObject.h"
39 #include "PdfXRef.h"
40 #include "PdfXRefStream.h"
41 #include "PdfDefinesPrivate.h"
42
43 namespace PoDoFo {
44
PdfImmediateWriter(PdfOutputDevice * pDevice,PdfVecObjects * pVecObjects,const PdfObject * pTrailer,EPdfVersion eVersion,PdfEncrypt * pEncrypt,EPdfWriteMode eWriteMode)45 PdfImmediateWriter::PdfImmediateWriter( PdfOutputDevice* pDevice, PdfVecObjects* pVecObjects,
46 const PdfObject* pTrailer, EPdfVersion eVersion,
47 PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode )
48 : PdfWriter( pVecObjects ), m_pParent( pVecObjects ),
49 m_pDevice( pDevice ), m_pLast( NULL ), m_bOpenStream( false )
50 {
51 if( m_pTrailer )
52 delete m_pTrailer;
53 m_pTrailer = new PdfObject( *pTrailer );
54
55 // register as observer for PdfVecObjects
56 m_pParent->Attach( this );
57 // register as stream factory for PdfVecObjects
58 m_pParent->SetStreamFactory( this );
59
60 this->CreateFileIdentifier( m_identifier, m_pTrailer );
61 // setup encryption
62 if( pEncrypt )
63 {
64 this->SetEncrypted( *pEncrypt );
65 m_pEncrypt->GenerateEncryptionKey( m_identifier );
66 }
67
68 // start with writing the header
69 this->SetPdfVersion( eVersion );
70 this->SetWriteMode( eWriteMode );
71 this->WritePdfHeader( m_pDevice );
72
73 m_pXRef = m_bXRefStream ? new PdfXRefStream( m_vecObjects, this ) : new PdfXRef();
74
75 }
76
~PdfImmediateWriter()77 PdfImmediateWriter::~PdfImmediateWriter()
78 {
79 if( m_pParent )
80 m_pParent->Detach( this );
81
82 delete m_pXRef;
83 }
84
WriteObject(const PdfObject * pObject)85 void PdfImmediateWriter::WriteObject( const PdfObject* pObject )
86 {
87 const int endObjLenght = 7;
88
89 this->FinishLastObject();
90
91 m_pXRef->AddObject( pObject->Reference(), m_pDevice->Tell(), true );
92 pObject->WriteObject( m_pDevice, this->GetWriteMode(), m_pEncrypt );
93 // Make sure, no one will add keys now to the object
94 const_cast<PdfObject*>(pObject)->SetImmutable(true);
95
96 // Let's cheat a bit:
97 // pObject has written an "endobj\n" as last data to the file.
98 // we simply overwrite this string with "stream\n" which
99 // has excatly the same length.
100 m_pDevice->Seek( m_pDevice->Tell() - endObjLenght );
101 m_pDevice->Print( "stream\n" );
102 m_pLast = const_cast<PdfObject*>(pObject);
103 }
104
ParentDestructed()105 void PdfImmediateWriter::ParentDestructed()
106 {
107 m_pParent = NULL;
108 }
109
Finish()110 void PdfImmediateWriter::Finish()
111 {
112 // write all objects which are still in RAM
113 this->FinishLastObject();
114
115 // setup encrypt dictionary
116 if( m_pEncrypt )
117 {
118 // Add our own Encryption dictionary
119 m_pEncryptObj = m_vecObjects->CreateObject();
120 m_pEncrypt->CreateEncryptionDictionary( m_pEncryptObj->GetDictionary() );
121 }
122
123 this->WritePdfObjects( m_pDevice, *m_pParent, m_pXRef );
124
125 // write the XRef
126 pdf_uint64 lXRefOffset = static_cast<pdf_uint64>( m_pDevice->Tell() );
127 m_pXRef->Write( m_pDevice );
128
129 // XRef streams contain the trailer in the XRef
130 if( !m_bXRefStream )
131 {
132 PdfObject trailer;
133
134 // if we have a dummy offset we write also a prev entry to the trailer
135 FillTrailerObject( &trailer, m_pXRef->GetSize(), false );
136
137 m_pDevice->Print("trailer\n");
138 trailer.WriteObject( m_pDevice, this->GetWriteMode(), NULL );
139 }
140
141 m_pDevice->Print( "startxref\n%" PDF_FORMAT_UINT64 "\n%%%%EOF\n", lXRefOffset );
142 m_pDevice->Flush();
143
144 // we are done now
145 m_pParent->Detach( this );
146 m_pParent = NULL;
147 }
148
CreateStream(PdfObject * pParent)149 PdfStream* PdfImmediateWriter::CreateStream( PdfObject* pParent )
150 {
151 return m_bOpenStream ?
152 static_cast<PdfStream*>(new PdfMemStream( pParent )) :
153 static_cast<PdfStream*>(new PdfFileStream( pParent, m_pDevice ));
154 }
155
FinishLastObject()156 void PdfImmediateWriter::FinishLastObject()
157 {
158 if( m_pLast )
159 {
160 m_pDevice->Print( "\nendstream\n" );
161 m_pDevice->Print( "endobj\n" );
162
163 delete m_pParent->RemoveObject( m_pLast->Reference(), false );
164 m_pLast = NULL;
165
166 }
167 }
168
BeginAppendStream(const PdfStream * pStream)169 void PdfImmediateWriter::BeginAppendStream( const PdfStream* pStream )
170 {
171 const PdfFileStream* pFileStream = dynamic_cast<const PdfFileStream*>(pStream );
172 if( pFileStream )
173 {
174 // Only one open file stream is allowed at a time
175 PODOFO_ASSERT( !m_bOpenStream );
176 m_bOpenStream = true;
177
178 if( m_pEncrypt )
179 const_cast<PdfFileStream*>(pFileStream)->SetEncrypted( m_pEncrypt );
180 }
181 }
182
EndAppendStream(const PdfStream * pStream)183 void PdfImmediateWriter::EndAppendStream( const PdfStream* pStream )
184 {
185 const PdfFileStream* pFileStream = dynamic_cast<const PdfFileStream*>(pStream );
186 if( pFileStream )
187 {
188 // A PdfFileStream has to be opened before
189 PODOFO_ASSERT( m_bOpenStream );
190 m_bOpenStream = false;
191 }
192 }
193
194 };
195
196