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 #include "PdfDefines.h"
35 #include "PdfFilter.h"
36
37 #include "PdfArray.h"
38 #include "PdfDictionary.h"
39 #include "PdfFiltersPrivate.h"
40 #include "PdfOutputStream.h"
41 #include "PdfDefinesPrivate.h"
42
43 namespace PoDoFo {
44
45 // All known filters
46 static const char* aszFilters[] = {
47 "ASCIIHexDecode",
48 "ASCII85Decode",
49 "LZWDecode",
50 "FlateDecode",
51 "RunLengthDecode",
52 "CCITTFaxDecode",
53 "JBIG2Decode",
54 "DCTDecode",
55 "JPXDecode",
56 "Crypt",
57 NULL
58 };
59
60 static const char* aszShortFilters[] = {
61 "AHx",
62 "A85",
63 "LZW",
64 "Fl",
65 "RL",
66 "CCF",
67 "", ///< There is no shortname for JBIG2Decode
68 "DCT",
69 "", ///< There is no shortname for JPXDecode
70 "", ///< There is no shortname for Crypt
71 NULL
72 };
73
74 /** Create a filter that is a PdfOutputStream.
75 *
76 * All data written to this stream is encoded using a
77 * filter and written to another PdfOutputStream.
78 *
79 * The passed output stream is owned by this PdfOutputStream
80 * and deleted along with it.
81 */
82 class PdfFilteredEncodeStream : public PdfOutputStream{
83 public:
84 /** Create a filtered output stream.
85 *
86 * All data written to this stream is encoded using the passed filter type
87 * and written to the passed output stream which will be deleted
88 * by this PdfFilteredEncodeStream.
89 *
90 * \param pOutputStream write all data to this output stream after encoding the data.
91 * \param eFilter use this filter for encoding.
92 * \param bOwnStream if true pOutputStream will be deleted along with this filter
93 */
PdfFilteredEncodeStream(PdfOutputStream * pOutputStream,const EPdfFilter eFilter,bool bOwnStream)94 PdfFilteredEncodeStream( PdfOutputStream* pOutputStream, const EPdfFilter eFilter, bool bOwnStream )
95 : m_pOutputStream( pOutputStream ), m_pFilter( NULL )
96 {
97 m_pFilter = PdfFilterFactory::Create( eFilter );
98
99 if( !m_pFilter )
100 {
101 PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
102 }
103
104 m_pFilter->BeginEncode( pOutputStream );
105
106 if( !bOwnStream )
107 m_pOutputStream = NULL;
108 }
109
~PdfFilteredEncodeStream()110 virtual ~PdfFilteredEncodeStream()
111 {
112 delete m_pOutputStream;
113 delete m_pFilter;
114 }
115
116 /** Write data to the output stream
117 *
118 * \param pBuffer the data is read from this buffer
119 * \param lLen the size of the buffer
120 */
Write(const char * pBuffer,pdf_long lLen)121 virtual pdf_long Write( const char* pBuffer, pdf_long lLen )
122 {
123 m_pFilter->EncodeBlock( pBuffer, lLen );
124
125 return 0;
126 }
127
Close()128 virtual void Close()
129 {
130 m_pFilter->EndEncode();
131 }
132
133 private:
134 PdfOutputStream* m_pOutputStream;
135 PdfFilter* m_pFilter;
136 };
137
138 /** Create a filter that is a PdfOutputStream.
139 *
140 * All data written to this stream is decoded using a
141 * filter and written to another PdfOutputStream.
142 *
143 * The passed output stream is owned by this PdfOutputStream
144 * and deleted along with it (optionally, see constructor).
145 */
146 class PdfFilteredDecodeStream : public PdfOutputStream {
147 public:
148 /** Create a filtered output stream.
149 *
150 * All data written to this stream is decoded using the passed filter type
151 * and written to the passed output stream which will be deleted
152 * by this PdfFilteredDecodeStream if the parameter bOwnStream is true.
153 *
154 * \param pOutputStream write all data to this output stream after decoding the data.
155 * The PdfOutputStream is deleted along with this object if bOwnStream is true.
156 * \param eFilter use this filter for decoding.
157 * \param bOwnStream if true pOutputStream will be deleted along with this stream
158 * \param pDecodeParms additional parameters for decoding
159 */
PdfFilteredDecodeStream(PdfOutputStream * pOutputStream,const EPdfFilter eFilter,bool bOwnStream,const PdfDictionary * pDecodeParms=NULL)160 PdfFilteredDecodeStream( PdfOutputStream* pOutputStream, const EPdfFilter eFilter, bool bOwnStream,
161 const PdfDictionary* pDecodeParms = NULL )
162 : m_pOutputStream( pOutputStream ), m_pFilter( NULL ), m_bFilterFailed( false )
163 {
164 m_pFilter = PdfFilterFactory::Create( eFilter );
165 if( !m_pFilter )
166 {
167 PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
168 }
169
170 m_pFilter->BeginDecode( pOutputStream, pDecodeParms );
171
172 if( !bOwnStream )
173 m_pOutputStream = NULL;
174 }
175
~PdfFilteredDecodeStream()176 virtual ~PdfFilteredDecodeStream()
177 {
178 delete m_pOutputStream;
179 delete m_pFilter;
180 }
181
182 /** Write data to the output stream
183 *
184 * \param pBuffer the data is read from this buffer
185 * \param lLen the size of the buffer
186 */
Write(const char * pBuffer,pdf_long lLen)187 virtual pdf_long Write( const char* pBuffer, pdf_long lLen )
188 {
189 try {
190 m_pFilter->DecodeBlock( pBuffer, lLen );
191 }
192 catch( PdfError & e )
193 {
194 e.AddToCallstack( __FILE__, __LINE__ );
195 m_bFilterFailed = true;
196 throw e;
197 }
198
199 return 0;
200 }
201
Close()202 virtual void Close()
203 {
204 try {
205 if( !m_bFilterFailed )
206 {
207 m_pFilter->EndDecode();
208 }
209 }
210 catch( PdfError & e )
211 {
212 std::ostringstream oss;
213 oss << "PdfFilter::EndDecode() failed in filter of type "
214 << PdfFilterFactory::FilterTypeToName( m_pFilter->GetType() ) << ".\n";
215 e.AddToCallstack( __FILE__, __LINE__, oss.str() );
216 m_bFilterFailed = true;
217 throw e;
218 }
219
220 }
221
222 private:
223 PdfOutputStream* m_pOutputStream;
224 PdfFilter* m_pFilter;
225 bool m_bFilterFailed;
226 };
227
228
229 // -----------------------------------------------------
230 // Actual PdfFilter code
231 // -----------------------------------------------------
232
233
PdfFilter()234 PdfFilter::PdfFilter()
235 : m_pOutputStream( NULL )
236 {
237 }
238
Encode(const char * pInBuffer,pdf_long lInLen,char ** ppOutBuffer,pdf_long * plOutLen) const239 void PdfFilter::Encode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen ) const
240 {
241 if( !this->CanEncode() )
242 {
243 PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
244 }
245
246 PdfMemoryOutputStream stream;
247
248 const_cast<PdfFilter*>(this)->BeginEncode( &stream );
249 const_cast<PdfFilter*>(this)->EncodeBlock( pInBuffer, lInLen );
250 const_cast<PdfFilter*>(this)->EndEncode();
251
252 *ppOutBuffer = stream.TakeBuffer();
253 *plOutLen = stream.GetLength();
254 }
255
Decode(const char * pInBuffer,pdf_long lInLen,char ** ppOutBuffer,pdf_long * plOutLen,const PdfDictionary * pDecodeParms) const256 void PdfFilter::Decode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen,
257 const PdfDictionary* pDecodeParms ) const
258 {
259 if( !this->CanDecode() )
260 {
261 PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter );
262 }
263
264 PdfMemoryOutputStream stream;
265
266 const_cast<PdfFilter*>(this)->BeginDecode( &stream, pDecodeParms );
267 const_cast<PdfFilter*>(this)->DecodeBlock( pInBuffer, lInLen );
268 const_cast<PdfFilter*>(this)->EndDecode();
269
270 *ppOutBuffer = stream.TakeBuffer();
271 *plOutLen = stream.GetLength();
272 }
273
274 // -----------------------------------------------------
275 // PdfFilterFactory code
276 // -----------------------------------------------------
277
PdfFilterFactory()278 PdfFilterFactory::PdfFilterFactory()
279 {
280 }
281
Create(const EPdfFilter eFilter)282 PdfFilter* PdfFilterFactory::Create( const EPdfFilter eFilter )
283 {
284 PdfFilter* pFilter = NULL;
285 switch( eFilter )
286 {
287 case ePdfFilter_None:
288 break;
289
290 case ePdfFilter_ASCIIHexDecode:
291 pFilter = new PdfHexFilter();
292 break;
293
294 case ePdfFilter_ASCII85Decode:
295 pFilter = new PdfAscii85Filter();
296 break;
297
298 case ePdfFilter_LZWDecode:
299 pFilter = new PdfLZWFilter();
300 break;
301
302 case ePdfFilter_FlateDecode:
303 pFilter = new PdfFlateFilter();
304 break;
305
306 case ePdfFilter_RunLengthDecode:
307 pFilter = new PdfRLEFilter();
308 break;
309
310 case ePdfFilter_DCTDecode:
311 #ifdef PODOFO_HAVE_JPEG_LIB
312 pFilter = new PdfDCTFilter();
313 break;
314 #else
315 break;
316 #endif // PODOFO_HAVE_JPEG_LIB
317
318 case ePdfFilter_CCITTFaxDecode:
319 #ifdef PODOFO_HAVE_TIFF_LIB
320 pFilter = new PdfCCITTFilter();
321 break;
322 #else
323 break;
324 #endif // PODOFO_HAVE_TIFF_LIB
325
326
327 case ePdfFilter_JBIG2Decode:
328 case ePdfFilter_JPXDecode:
329 case ePdfFilter_Crypt:
330 default:
331 break;
332 }
333
334 return pFilter;
335 }
336
CreateEncodeStream(const TVecFilters & filters,PdfOutputStream * pStream)337 PdfOutputStream* PdfFilterFactory::CreateEncodeStream( const TVecFilters & filters, PdfOutputStream* pStream )
338 {
339 TVecFilters::const_iterator it = filters.begin();
340
341 PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an EncodeStream from an empty list of filters" );
342
343 PdfFilteredEncodeStream* pFilter = new PdfFilteredEncodeStream( pStream, *it, false );
344 ++it;
345
346 while( it != filters.end() )
347 {
348 pFilter = new PdfFilteredEncodeStream( pFilter, *it, true );
349 ++it;
350 }
351
352 return pFilter;
353 }
354
CreateDecodeStream(const TVecFilters & filters,PdfOutputStream * pStream,const PdfDictionary * pDictionary)355 PdfOutputStream* PdfFilterFactory::CreateDecodeStream( const TVecFilters & filters, PdfOutputStream* pStream,
356 const PdfDictionary* pDictionary )
357 {
358 TVecFilters::const_reverse_iterator it = filters.rbegin();
359
360 PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an DecodeStream from an empty list of filters" );
361
362 // TODO: support arrays and indirect objects here and the short name /DP
363 if( pDictionary && pDictionary->HasKey( "DecodeParms" ) && pDictionary->GetKey( "DecodeParms" )->IsDictionary() )
364 pDictionary = &(pDictionary->GetKey( "DecodeParms" )->GetDictionary());
365
366 PdfFilteredDecodeStream* pFilterStream = new PdfFilteredDecodeStream( pStream, *it, false, pDictionary );
367 ++it;
368
369 while( it != filters.rend() )
370 {
371 pFilterStream = new PdfFilteredDecodeStream( pFilterStream, *it, true, pDictionary );
372 ++it;
373 }
374
375 return pFilterStream;
376 }
377
FilterNameToType(const PdfName & name,bool bSupportShortNames)378 EPdfFilter PdfFilterFactory::FilterNameToType( const PdfName & name, bool bSupportShortNames )
379 {
380 int i = 0;
381
382 while( aszFilters[i] )
383 {
384 if( name == aszFilters[i] )
385 return static_cast<EPdfFilter>(i);
386
387 ++i;
388 }
389
390 if( bSupportShortNames )
391 {
392 i = 0;
393 while( aszShortFilters[i] )
394 {
395 if( name == aszShortFilters[i] )
396 return static_cast<EPdfFilter>(i);
397
398 ++i;
399 }
400 }
401
402 PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFilter, name.GetName().c_str() );
403 }
404
FilterTypeToName(EPdfFilter eFilter)405 const char* PdfFilterFactory::FilterTypeToName( EPdfFilter eFilter )
406 {
407 return aszFilters[static_cast<int>(eFilter)];
408 }
409
CreateFilterList(const PdfObject * pObject)410 TVecFilters PdfFilterFactory::CreateFilterList( const PdfObject* pObject )
411 {
412 TVecFilters filters;
413
414 const PdfObject* pObj = NULL;
415
416 if( pObject->IsDictionary() && pObject->GetDictionary().HasKey( "Filter" ) )
417 pObj = pObject->GetIndirectKey( "Filter" );
418 else if( pObject->IsArray() )
419 pObj = pObject;
420 else if( pObject->IsName() )
421 pObj = pObject;
422
423
424 if (!pObj)
425 // Object had no /Filter key . Return a null filter list.
426 return filters;
427
428 if( pObj->IsName() )
429 filters.push_back( PdfFilterFactory::FilterNameToType( pObj->GetName() ) );
430 else if( pObj->IsArray() )
431 {
432 TCIVariantList it = pObj->GetArray().begin();
433
434 while( it != pObj->GetArray().end() )
435 {
436 if ( (*it).IsName() )
437 {
438 filters.push_back( PdfFilterFactory::FilterNameToType( (*it).GetName() ) );
439 }
440 else if ( (*it).IsReference() )
441 {
442 PdfObject* pFilter = pObject->GetOwner()->GetObject( (*it).GetReference() );
443 if( pFilter == NULL )
444 {
445 PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Filter array contained unexpected reference" );
446 }
447
448 filters.push_back( PdfFilterFactory::FilterNameToType( pFilter->GetName() ) );
449 }
450 else
451 {
452 PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Filter array contained unexpected non-name type" );
453 }
454
455 ++it;
456 }
457 }
458
459 return filters;
460 }
461
462 };
463