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