Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #if defined __SUNPRO_CC
31 : : #pragma disable_warn
32 : : #elif defined _MSC_VER
33 : : #pragma warning(push, 1)
34 : : #endif
35 : :
36 : : #include "pdfparse.hxx"
37 : :
38 : : // workaround windows compiler: do not include multi_pass.hpp
39 : : #include <boost/spirit/include/classic_core.hpp>
40 : : #include <boost/spirit/include/classic_utility.hpp>
41 : : #include <boost/spirit/include/classic_error_handling.hpp>
42 : : #include <boost/spirit/include/classic_file_iterator.hpp>
43 : : #include <boost/bind.hpp>
44 : : #include <string>
45 : :
46 : : #include <rtl/strbuf.hxx>
47 : : #include <rtl/memory.h>
48 : : #include <rtl/alloc.h>
49 : :
50 : : // disable warnings again because someone along the line has enabled them
51 : : #if defined __SUNPRO_CC
52 : : #pragma disable_warn
53 : : #elif defined _MSC_VER
54 : : #pragma warning(push, 1)
55 : : #endif
56 : :
57 : : using namespace boost::spirit;
58 : : using namespace pdfparse;
59 : :
60 : : using ::rtl::OString;
61 : : using ::rtl::OStringBuffer;
62 : :
63 : : class StringEmitContext : public EmitContext
64 : : {
65 : : OStringBuffer m_aBuf;
66 : : public:
67 : 0 : StringEmitContext() : EmitContext(), m_aBuf(256) {}
68 [ # # ]: 0 : virtual ~StringEmitContext() {}
69 : 0 : virtual bool write( const void* pBuf, unsigned int nLen ) throw()
70 : : {
71 : 0 : m_aBuf.append( (const sal_Char*)pBuf, nLen );
72 : 0 : return true;
73 : : }
74 : 0 : virtual unsigned int getCurPos() throw() { return m_aBuf.getLength(); }
75 : 0 : virtual bool copyOrigBytes( unsigned int nOrigOffset, unsigned int nLen ) throw()
76 : 0 : { return (nOrigOffset+nLen < static_cast<unsigned int>(m_aBuf.getLength()) ) ?
77 [ # # ]: 0 : write( m_aBuf.getStr() + nOrigOffset, nLen ) : false; }
78 : 0 : virtual unsigned int readOrigBytes( unsigned int nOrigOffset, unsigned int nLen, void* pBuf ) throw()
79 : : {
80 [ # # ]: 0 : if( nOrigOffset+nLen < static_cast<unsigned int>(m_aBuf.getLength()) )
81 : : {
82 : 0 : rtl_copyMemory( pBuf, m_aBuf.getStr()+nOrigOffset, nLen );
83 : 0 : return nLen;
84 : : }
85 : 0 : return 0;
86 : : }
87 : :
88 : 0 : OString getString() { return m_aBuf.makeStringAndClear(); }
89 : : };
90 : :
91 : : template< class iteratorT >
92 : : class PDFGrammar : public grammar< PDFGrammar<iteratorT> >
93 : : {
94 : : public:
95 : :
96 : 25 : PDFGrammar( const iteratorT& first )
97 [ + - ][ + - ]: 25 : : m_fDouble( 0.0 ), m_aGlobalBegin( first ) {}
[ + - ]
98 : 25 : ~PDFGrammar()
99 : : {
100 [ - + ]: 25 : if( !m_aObjectStack.empty() )
101 [ # # ][ # # ]: 0 : delete m_aObjectStack.front();
[ # # ]
102 [ + - ]: 25 : }
103 : :
104 : : double m_fDouble;
105 : : std::vector< unsigned int > m_aUIntStack;
106 : : std::vector< PDFEntry* > m_aObjectStack;
107 : : rtl::OString m_aErrorString;
108 : : iteratorT m_aGlobalBegin;
109 : :
110 : : public:
111 : : struct pdf_string_parser
112 : : {
113 : : typedef nil_t result_t;
114 : : template <typename ScannerT>
115 : : std::ptrdiff_t
116 : 30 : operator()(ScannerT const& scan, result_t&) const
117 : : {
118 : 30 : std::ptrdiff_t len = 0;
119 : :
120 : 30 : int nBraceLevel = 0;
121 [ + - ]: 840 : while( ! scan.at_end() )
122 : : {
123 : 840 : char c = *scan;
124 [ + + ]: 840 : if( c == ')' )
125 : : {
126 : 30 : nBraceLevel--;
127 [ + - ]: 30 : if( nBraceLevel < 0 )
128 : 30 : break;
129 : : }
130 [ - + ]: 810 : else if( c == '(' )
131 : 0 : nBraceLevel++;
132 [ - + ]: 810 : else if( c == '\\' ) // ignore escaped braces
133 : : {
134 : 0 : ++len;
135 : 0 : ++scan;
136 [ # # ]: 0 : if( scan.at_end() )
137 : 0 : break;
138 : : }
139 : 810 : ++len;
140 : 810 : ++scan;
141 : : }
142 [ - + ]: 30 : return scan.at_end() ? -1 : len;
143 : : }
144 : : };
145 : :
146 : : template< typename ScannerT >
147 [ + - ][ + - ]: 25 : struct definition
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
148 : : {
149 : 25 : definition( const PDFGrammar<iteratorT>& rSelf )
150 [ + - ][ + - ]: 25 : {
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
151 : 25 : PDFGrammar<iteratorT>* pSelf = const_cast< PDFGrammar<iteratorT>* >( &rSelf );
152 : :
153 : : // workaround workshop compiler: comment_p doesn't work
154 : : // comment = comment_p("%")[boost::bind(&PDFGrammar::pushComment, pSelf, _1, _2 )];
155 [ + - ][ + - ]: 25 : comment = lexeme_d[ (ch_p('%') >> *(~ch_p('\r') & ~ch_p('\n')) >> eol_p)[boost::bind(&PDFGrammar::pushComment, pSelf, _1, _2 )] ];
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
156 : :
157 [ + - ][ + - ]: 25 : boolean = (str_p("true") | str_p("false"))[boost::bind(&PDFGrammar::pushBool, pSelf, _1, _2)];
[ + - ][ + - ]
[ + - ][ + - ]
158 : :
159 : : // workaround workshop compiler: confix_p doesn't work
160 : : //stream = confix_p( "stream", *anychar_p, "endstream" )[boost::bind(&PDFGrammar::emitStream, pSelf, _1, _2 )];
161 [ + - ][ + - ]: 25 : stream = (str_p("stream") >> *(anychar_p - str_p("endstream")) >> str_p("endstream"))[boost::bind(&PDFGrammar::emitStream, pSelf, _1, _2 )];
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
162 : :
163 [ + - ][ + - ]: 25 : name = lexeme_d[
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
164 : : ch_p('/')
165 : : >> (*(anychar_p-chset_p("\t\n\f\r ()<>[]{}/%")-ch_p('\0')))
166 : : [boost::bind(&PDFGrammar::pushName, pSelf, _1, _2)] ];
167 : :
168 : : // workaround workshop compiler: confix_p doesn't work
169 : : //stringtype = ( confix_p("(",*anychar_p, ")") |
170 : : // confix_p("<",*xdigit_p, ">") )
171 : : // [boost::bind(&PDFGrammar::pushString,pSelf, _1, _2)];
172 : :
173 [ + - ][ + - ]: 25 : stringtype = ( ( ch_p('(') >> functor_parser<pdf_string_parser>() >> ch_p(')') ) |
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
174 : : ( ch_p('<') >> *xdigit_p >> ch_p('>') ) )
175 : : [boost::bind(&PDFGrammar::pushString,pSelf, _1, _2)];
176 : :
177 [ + - ][ + - ]: 25 : null_object = str_p( "null" )[boost::bind(&PDFGrammar::pushNull, pSelf, _1, _2)];
[ + - ][ + - ]
178 : :
179 : : #ifdef USE_ASSIGN_ACTOR
180 : : objectref = ( uint_p[push_back_a(pSelf->m_aUIntStack)]
181 : : >> uint_p[push_back_a(pSelf->m_aUIntStack)]
182 : : >> ch_p('R')
183 : : >> eps_p
184 : : )[boost::bind(&PDFGrammar::pushObjectRef, pSelf, _1, _2)];
185 : : #else
186 [ + - ][ + - ]: 25 : objectref = ( uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
187 : : >> uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
188 : : >> ch_p('R')
189 : : >> eps_p
190 : : )[boost::bind(&PDFGrammar::pushObjectRef, pSelf, _1, _2)];
191 : : #endif
192 : :
193 : : #ifdef USE_ASSIGN_ACTOR
194 : : simple_type = objectref | name |
195 : : ( real_p[assign_a(pSelf->m_fDouble)] >> eps_p )
196 : : [boost::bind(&PDFGrammar::pushDouble, pSelf, _1, _2)]
197 : : | stringtype | boolean | null_object;
198 : : #else
199 [ + - ][ + - ]: 25 : simple_type = objectref | name |
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
200 : : ( real_p[boost::bind(&PDFGrammar::assign_action_double, pSelf, _1)] >> eps_p )
201 : : [boost::bind(&PDFGrammar::pushDouble, pSelf, _1, _2)]
202 : : | stringtype | boolean | null_object;
203 : : #endif
204 : :
205 [ + - ][ + - ]: 25 : dict_begin = str_p( "<<" )[boost::bind(&PDFGrammar::beginDict, pSelf, _1, _2)];
[ + - ][ + - ]
206 [ + - ][ + - ]: 25 : dict_end = str_p( ">>" )[boost::bind(&PDFGrammar::endDict, pSelf, _1, _2)];
[ + - ][ + - ]
207 : :
208 [ + - ][ + - ]: 25 : array_begin = str_p("[")[boost::bind(&PDFGrammar::beginArray,pSelf, _1, _2)];
[ + - ][ + - ]
209 [ + - ][ + - ]: 25 : array_end = str_p("]")[boost::bind(&PDFGrammar::endArray,pSelf, _1, _2)];
[ + - ][ + - ]
210 : :
211 : : #ifdef USE_ASSIGN_ACTOR
212 : : object_begin= uint_p[push_back_a(pSelf->m_aUIntStack)]
213 : : >> uint_p[push_back_a(pSelf->m_aUIntStack)]
214 : : >> str_p("obj" )[boost::bind(&PDFGrammar::beginObject, pSelf, _1, _2)];
215 : : #else
216 [ + - ][ + - ]: 25 : object_begin= uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
217 : : >> uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
218 : : >> str_p("obj" )[boost::bind(&PDFGrammar::beginObject, pSelf, _1, _2)];
219 : : #endif
220 [ + - ][ + - ]: 25 : object_end = str_p( "endobj" )[boost::bind(&PDFGrammar::endObject, pSelf, _1, _2)];
[ + - ][ + - ]
221 : :
222 [ + - ][ + - ]: 25 : xref = str_p( "xref" ) >> uint_p >> uint_p
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
223 : : >> lexeme_d[
224 : : +( repeat_p(10)[digit_p]
225 : : >> blank_p
226 : : >> repeat_p(5)[digit_p]
227 : : >> blank_p
228 : : >> ( ch_p('n') | ch_p('f') )
229 : : >> repeat_p(2)[space_p]
230 : : ) ];
231 : :
232 [ + - ][ + - ]: 25 : dict_element= dict_begin | comment | simple_type
[ + - ][ + - ]
[ + - ][ + - ]
233 : : | array_begin | array_end | dict_end;
234 : :
235 [ + - ][ + - ]: 25 : object = object_begin
[ + - ][ + - ]
[ + - ][ + - ]
236 : : >> *dict_element
237 : : >> !stream
238 : : >> object_end;
239 : :
240 [ + - ][ + - ]: 25 : trailer = str_p( "trailer" )[boost::bind(&PDFGrammar::beginTrailer,pSelf,_1,_2)]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
241 : : >> *dict_element
242 : : >> str_p("startxref")
243 : : >> uint_p
244 : : >> str_p("%%EOF")[boost::bind(&PDFGrammar::endTrailer,pSelf,_1,_2)];
245 : :
246 : : #ifdef USE_ASSIGN_ACTOR
247 : : pdfrule = ! (lexeme_d[
248 : : str_p( "%PDF-" )
249 : : >> uint_p[push_back_a(pSelf->m_aUIntStack)]
250 : : >> ch_p('.')
251 : : >> uint_p[push_back_a(pSelf->m_aUIntStack)]
252 : : >> *((~ch_p('\r') & ~ch_p('\n')))
253 : : >> eol_p
254 : : ])[boost::bind(&PDFGrammar::haveFile,pSelf, _1, _2)]
255 : : >> *( comment | object | ( xref >> trailer ) );
256 : : #else
257 [ + - ][ + - ]: 25 : pdfrule = ! (lexeme_d[
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
258 : : str_p( "%PDF-" )
259 : : >> uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
260 : : >> ch_p('.')
261 : : >> uint_p[boost::bind(&PDFGrammar::push_back_action_uint, pSelf, _1)]
262 : : >> *((~ch_p('\r') & ~ch_p('\n')))
263 : : >> eol_p
264 : : ])[boost::bind(&PDFGrammar::haveFile,pSelf, _1, _2)]
265 : : >> *( comment | object | ( xref >> trailer ) );
266 : : #endif
267 : 25 : }
268 : : rule< ScannerT > comment, stream, boolean, name, stringtype, null_object, simple_type,
269 : : objectref, array, value, dict_element, dict_begin, dict_end,
270 : : array_begin, array_end, object, object_begin, object_end,
271 : : xref, trailer, pdfrule;
272 : :
273 : 25 : const rule< ScannerT >& start() const { return pdfrule; }
274 : : };
275 : :
276 : : #ifndef USE_ASSIGN_ACTOR
277 : 3555 : void push_back_action_uint( unsigned int i )
278 : : {
279 : 3555 : m_aUIntStack.push_back( i );
280 : 3555 : }
281 : 1455 : void assign_action_double( double d )
282 : : {
283 : 1455 : m_fDouble = d;
284 : 1455 : }
285 : : #endif
286 : :
287 : 0 : void parseError( const char* pMessage, iteratorT pLocation )
288 : : {
289 [ # # ]: 0 : throw_( pLocation, pMessage );
290 : 0 : }
291 : :
292 : 2535 : rtl::OString iteratorToString( iteratorT first, iteratorT last ) const
293 : : {
294 : 2535 : rtl::OStringBuffer aStr( 32 );
295 [ + - ][ + + ]: 23535 : while( first != last )
296 : : {
297 [ + - ][ + - ]: 21000 : aStr.append( *first );
298 [ + - ]: 21000 : ++first;
299 : : }
300 : 2535 : return aStr.makeStringAndClear();
301 : : }
302 : :
303 : 15 : void haveFile( iteratorT pBegin, SAL_UNUSED_PARAMETER iteratorT /*pEnd*/ )
304 : : {
305 [ + - ]: 15 : if( m_aObjectStack.empty() )
306 : : {
307 [ + - ]: 15 : PDFFile* pFile = new PDFFile();
308 : 15 : pFile->m_nMinor = m_aUIntStack.back();
309 : 15 : m_aUIntStack.pop_back();
310 : 15 : pFile->m_nMajor = m_aUIntStack.back();
311 : 15 : m_aUIntStack.pop_back();
312 [ + - ]: 15 : m_aObjectStack.push_back( pFile );
313 : : }
314 : : else
315 [ # # ]: 0 : parseError( "found file header in unusual place", pBegin );
316 : 15 : }
317 : :
318 : 15 : void pushComment( iteratorT first, iteratorT last )
319 : : {
320 : : // add a comment to the current stack element
321 : : PDFComment* pComment =
322 [ + - ][ + - ]: 15 : new PDFComment(iteratorToString(first,last));
[ + - ][ + - ]
[ + - ]
323 [ - + ]: 15 : if( m_aObjectStack.empty() )
324 [ # # ][ # # ]: 0 : m_aObjectStack.push_back( new PDFPart() );
325 [ - + ]: 15 : PDFContainer* pContainer = dynamic_cast<PDFContainer*>(m_aObjectStack.back());
326 [ - + ]: 15 : if( pContainer == NULL )
327 [ # # ]: 0 : parseError( "comment without container", first );
328 [ + - ]: 15 : pContainer->m_aSubElements.push_back( pComment );
329 : 15 : }
330 : :
331 : 5040 : void insertNewValue( PDFEntry* pNewValue, iteratorT pPos )
332 : : {
333 : 5040 : PDFContainer* pContainer = NULL;
334 : 5040 : const char* pMsg = NULL;
335 [ + - ][ - + ]: 5040 : if( ! m_aObjectStack.empty() &&
[ + - ][ + - ]
336 : : (pContainer = dynamic_cast<PDFContainer*>(m_aObjectStack.back())) != NULL )
337 : : {
338 [ + - ][ + + ]: 5040 : if( dynamic_cast<PDFDict*>(pContainer) == NULL &&
[ + - ][ + + ]
[ + + ]
339 : : dynamic_cast<PDFArray*>(pContainer) == NULL )
340 : : {
341 [ - + ]: 390 : PDFObject* pObj = dynamic_cast<PDFObject*>(pContainer);
342 [ + + ]: 390 : if( pObj )
343 : : {
344 [ + - ]: 375 : if( pObj->m_pObject == NULL )
345 : 375 : pObj->m_pObject = pNewValue;
346 : : else
347 : : {
348 : 0 : pMsg = "second value for object";
349 : 0 : pContainer = NULL;
350 : : }
351 : : }
352 [ + - ][ + - ]: 15 : else if( dynamic_cast<PDFDict*>(pNewValue) )
[ + - ]
353 : : {
354 [ - + ]: 15 : PDFTrailer* pTrailer = dynamic_cast<PDFTrailer*>(pContainer);
355 [ + - ]: 15 : if( pTrailer )
356 : : {
357 [ + - ]: 15 : if( pTrailer->m_pDict == NULL )
358 [ - + ]: 15 : pTrailer->m_pDict = dynamic_cast<PDFDict*>(pNewValue);
359 : : else
360 : 0 : pContainer = NULL;
361 : : }
362 : : else
363 : 0 : pContainer = NULL;
364 : : }
365 : : else
366 : 0 : pContainer = NULL;
367 : : }
368 : : }
369 [ + - ]: 5040 : if( pContainer )
370 : 5040 : pContainer->m_aSubElements.push_back( pNewValue );
371 : : else
372 : : {
373 [ # # ]: 0 : if( ! pMsg )
374 : : {
375 [ # # ][ # # ]: 0 : if( dynamic_cast<PDFContainer*>(pNewValue) )
[ # # ]
376 : 0 : pMsg = "array without container";
377 : : else
378 : 0 : pMsg = "value without container";
379 : : }
380 [ # # ]: 0 : delete pNewValue;
381 [ # # ]: 0 : parseError( pMsg, pPos );
382 : : }
383 : 5040 : }
384 : :
385 : 2430 : void pushName( iteratorT first, iteratorT last )
386 : : {
387 [ + - ][ + - ]: 2430 : insertNewValue( new PDFName(iteratorToString(first,last)), first );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
388 : 2430 : }
389 : :
390 : 1455 : void pushDouble( iteratorT first, SAL_UNUSED_PARAMETER iteratorT /*last*/ )
391 : : {
392 [ + - ][ + - ]: 1455 : insertNewValue( new PDFNumber(m_fDouble), first );
[ + - ]
393 : 1455 : }
394 : :
395 : 90 : void pushString( iteratorT first, iteratorT last )
396 : : {
397 [ + - ][ + - ]: 90 : insertNewValue( new PDFString(iteratorToString(first,last)), first );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
398 : 90 : }
399 : :
400 : 15 : void pushBool( iteratorT first, iteratorT last )
401 : : {
402 [ + - ][ + - ]: 15 : insertNewValue( new PDFBool( (last-first == 4) ), first );
[ + - ][ + - ]
403 : 15 : }
404 : :
405 : 30 : void pushNull( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
406 : : {
407 [ + - ][ + - ]: 30 : insertNewValue( new PDFNull(), first );
[ + - ]
408 : 30 : }
409 : :
410 : :
411 : 375 : void beginObject( iteratorT first, SAL_UNUSED_PARAMETER iteratorT /*last*/ )
412 : : {
413 [ - + ]: 375 : if( m_aObjectStack.empty() )
414 [ # # ][ # # ]: 0 : m_aObjectStack.push_back( new PDFPart() );
415 : :
416 : 375 : unsigned int nGeneration = m_aUIntStack.back();
417 : 375 : m_aUIntStack.pop_back();
418 : 375 : unsigned int nObject = m_aUIntStack.back();
419 : 375 : m_aUIntStack.pop_back();
420 : :
421 [ + - ]: 375 : PDFObject* pObj = new PDFObject( nObject, nGeneration );
422 : 375 : pObj->m_nOffset = first - m_aGlobalBegin;
423 : :
424 [ - + ]: 375 : PDFContainer* pContainer = dynamic_cast<PDFContainer*>(m_aObjectStack.back());
425 [ + - ][ + - ]: 375 : if( pContainer &&
[ - + ][ # # ]
[ # # ][ + - ]
426 : : ( dynamic_cast<PDFFile*>(pContainer) ||
427 : : dynamic_cast<PDFPart*>(pContainer) ) )
428 : : {
429 [ + - ]: 375 : pContainer->m_aSubElements.push_back( pObj );
430 [ + - ]: 375 : m_aObjectStack.push_back( pObj );
431 : : }
432 : : else
433 [ # # ]: 0 : parseError( "object in wrong place", first );
434 : 375 : }
435 : :
436 : 375 : void endObject( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
437 : : {
438 [ - + ]: 375 : if( m_aObjectStack.empty() )
439 [ # # ]: 0 : parseError( "endobj without obj", first );
440 [ + - ][ - + ]: 375 : else if( dynamic_cast<PDFObject*>(m_aObjectStack.back()) == NULL )
[ - + ]
441 [ # # ]: 0 : parseError( "spurious endobj", first );
442 : : else
443 : 375 : m_aObjectStack.pop_back();
444 : 375 : }
445 : :
446 : 420 : void pushObjectRef( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
447 : : {
448 : 420 : unsigned int nGeneration = m_aUIntStack.back();
449 : 420 : m_aUIntStack.pop_back();
450 : 420 : unsigned int nObject = m_aUIntStack.back();
451 : 420 : m_aUIntStack.pop_back();
452 [ + - ][ + - ]: 420 : insertNewValue( new PDFObjectRef(nObject,nGeneration), first );
[ + - ]
453 : 420 : }
454 : :
455 : 375 : void beginDict( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
456 : : {
457 [ + - ]: 375 : PDFDict* pDict = new PDFDict();
458 : 375 : pDict->m_nOffset = first - m_aGlobalBegin;
459 : :
460 [ + - ]: 375 : insertNewValue( pDict, first );
461 : : // will not come here if insertion fails (exception)
462 [ + - ]: 375 : m_aObjectStack.push_back( pDict );
463 : 375 : }
464 : 375 : void endDict( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
465 : : {
466 : 375 : PDFDict* pDict = NULL;
467 [ - + ]: 375 : if( m_aObjectStack.empty() )
468 [ # # ]: 0 : parseError( "dictionary end without begin", first );
469 [ - + ][ - + ]: 375 : else if( (pDict = dynamic_cast<PDFDict*>(m_aObjectStack.back())) == NULL )
470 [ # # ]: 0 : parseError( "spurious dictionary end", first );
471 : : else
472 : 375 : m_aObjectStack.pop_back();
473 : :
474 : 375 : PDFEntry* pOffender = pDict->buildMap();
475 [ - + ]: 375 : if( pOffender )
476 : : {
477 [ # # ]: 0 : StringEmitContext aCtx;
478 : 0 : aCtx.write( "offending dictionary element: ", 30 );
479 [ # # ]: 0 : pOffender->emit( aCtx );
480 : 0 : m_aErrorString = aCtx.getString();
481 [ # # ][ # # ]: 0 : parseError( m_aErrorString.getStr(), first );
[ # # ][ # # ]
482 : : }
483 : 375 : }
484 : :
485 : 225 : void beginArray( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
486 : : {
487 [ + - ]: 225 : PDFArray* pArray = new PDFArray();
488 : 225 : pArray->m_nOffset = first - m_aGlobalBegin;
489 : :
490 [ + - ]: 225 : insertNewValue( pArray, first );
491 : : // will not come here if insertion fails (exception)
492 [ + - ]: 225 : m_aObjectStack.push_back( pArray );
493 : 225 : }
494 : :
495 : 225 : void endArray( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
496 : : {
497 [ - + ]: 225 : if( m_aObjectStack.empty() )
498 [ # # ]: 0 : parseError( "array end without begin", first );
499 [ + - ][ - + ]: 225 : else if( dynamic_cast<PDFArray*>(m_aObjectStack.back()) == NULL )
[ - + ]
500 [ # # ]: 0 : parseError( "spurious array end", first );
501 : : else
502 : 225 : m_aObjectStack.pop_back();
503 : 225 : }
504 : :
505 : 120 : void emitStream( iteratorT first, iteratorT last )
506 : : {
507 [ - + ]: 120 : if( m_aObjectStack.empty() )
508 [ # # ]: 0 : parseError( "stream without object", first );
509 [ - + ]: 120 : PDFObject* pObj = dynamic_cast<PDFObject*>(m_aObjectStack.back());
510 [ + - ][ + - ]: 120 : if( pObj && pObj->m_pObject )
511 : : {
512 [ - + ]: 120 : if( pObj->m_pStream )
513 [ # # ]: 0 : parseError( "multiple streams in object", first );
514 : :
515 [ - + ]: 120 : PDFDict* pDict = dynamic_cast<PDFDict*>(pObj->m_pObject);
516 [ + - ]: 120 : if( pDict )
517 : : {
518 [ + - ]: 120 : PDFStream* pStream = new PDFStream( first - m_aGlobalBegin, last - m_aGlobalBegin, pDict );
519 : :
520 : 120 : pObj->m_pStream = pStream;
521 [ + - ]: 120 : pObj->m_aSubElements.push_back( pStream );
522 : : }
523 : : }
524 : : else
525 [ # # ]: 0 : parseError( "stream without object", first );
526 : 120 : }
527 : :
528 : 15 : void beginTrailer( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
529 : : {
530 [ - + ]: 15 : if( m_aObjectStack.empty() )
531 [ # # ][ # # ]: 0 : m_aObjectStack.push_back( new PDFPart() );
532 : :
533 [ + - ]: 15 : PDFTrailer* pTrailer = new PDFTrailer();
534 : 15 : pTrailer->m_nOffset = first - m_aGlobalBegin;
535 : :
536 [ - + ]: 15 : PDFContainer* pContainer = dynamic_cast<PDFContainer*>(m_aObjectStack.back());
537 [ + - ][ + - ]: 15 : if( pContainer &&
[ - + ][ # # ]
[ # # ][ + - ]
538 : : ( dynamic_cast<PDFFile*>(pContainer) ||
539 : : dynamic_cast<PDFPart*>(pContainer) ) )
540 : : {
541 [ + - ]: 15 : pContainer->m_aSubElements.push_back( pTrailer );
542 [ + - ]: 15 : m_aObjectStack.push_back( pTrailer );
543 : : }
544 : : else
545 [ # # ]: 0 : parseError( "trailer in wrong place", first );
546 : 15 : }
547 : :
548 : 15 : void endTrailer( iteratorT first, SAL_UNUSED_PARAMETER iteratorT )
549 : : {
550 [ - + ]: 15 : if( m_aObjectStack.empty() )
551 [ # # ]: 0 : parseError( "%%EOF without trailer", first );
552 [ + - ][ - + ]: 15 : else if( dynamic_cast<PDFTrailer*>(m_aObjectStack.back()) == NULL )
[ - + ]
553 [ # # ]: 0 : parseError( "spurious %%EOF", first );
554 : : else
555 : 15 : m_aObjectStack.pop_back();
556 : 15 : }
557 : : };
558 : :
559 : : #ifdef WIN32
560 : : PDFEntry* PDFReader::read( const char* pBuffer, unsigned int nLen )
561 : : {
562 : : PDFGrammar<const char*> aGrammar( pBuffer );
563 : :
564 : : try
565 : : {
566 : : #if OSL_DEBUG_LEVEL > 1
567 : : boost::spirit::parse_info<const char*> aInfo =
568 : : #endif
569 : : boost::spirit::parse( pBuffer,
570 : : pBuffer+nLen,
571 : : aGrammar,
572 : : boost::spirit::space_p );
573 : : #if OSL_DEBUG_LEVEL > 1
574 : : fprintf( stderr, "parseinfo: stop = %p (buff=%p, offset = %d), hit = %s, full = %s, length = %d\n",
575 : : aInfo.stop, pBuffer, aInfo.stop - pBuffer,
576 : : aInfo.hit ? "true" : "false",
577 : : aInfo.full ? "true" : "false",
578 : : (int)aInfo.length );
579 : : #endif
580 : : }
581 : : catch( const parser_error<const char*, const char*>& rError )
582 : : {
583 : : #if OSL_DEBUG_LEVEL > 1
584 : : fprintf( stderr, "parse error: %s at buffer pos %u\nobject stack:\n",
585 : : rError.descriptor, rError.where - pBuffer );
586 : : unsigned int nElem = aGrammar.m_aObjectStack.size();
587 : : for( unsigned int i = 0; i < nElem; i++ )
588 : : {
589 : : fprintf( stderr, " %s\n", typeid( *(aGrammar.m_aObjectStack[i]) ).name() );
590 : : }
591 : : #endif
592 : : }
593 : :
594 : : PDFEntry* pRet = NULL;
595 : : unsigned int nEntries = aGrammar.m_aObjectStack.size();
596 : : if( nEntries == 1 )
597 : : {
598 : : pRet = aGrammar.m_aObjectStack.back();
599 : : aGrammar.m_aObjectStack.pop_back();
600 : : }
601 : : #if OSL_DEBUG_LEVEL > 1
602 : : else if( nEntries > 1 )
603 : : fprintf( stderr, "error got %u stack objects in parse\n", nEntries );
604 : : #endif
605 : :
606 : : return pRet;
607 : : }
608 : : #endif
609 : :
610 : 25 : PDFEntry* PDFReader::read( const char* pFileName )
611 : : {
612 : : #ifdef WIN32
613 : : /* #i106583#
614 : : since converting to boost 1.39 file_iterator does not work anymore on all Windows systems
615 : : C++ stdlib istream_iterator does not allow "-" apparently
616 : : using spirit 2.0 doesn't work in our environment with the MSC
617 : :
618 : : So for the time being bite the bullet and read the whole file.
619 : : FIXME: give Spirit 2.x another try when we upgrade boost again.
620 : : */
621 : : PDFEntry* pRet = NULL;
622 : : FILE* fp = fopen( pFileName, "rb" );
623 : : if( fp )
624 : : {
625 : : fseek( fp, 0, SEEK_END );
626 : : unsigned int nLen = (unsigned int)ftell( fp );
627 : : fseek( fp, 0, SEEK_SET );
628 : : char* pBuf = (char*)rtl_allocateMemory( nLen );
629 : : if( pBuf )
630 : : {
631 : : fread( pBuf, 1, nLen, fp );
632 : : pRet = read( pBuf, nLen );
633 : : rtl_freeMemory( pBuf );
634 : : }
635 : : fclose( fp );
636 : : }
637 : : return pRet;
638 : : #else
639 [ + - ][ + - ]: 25 : file_iterator<> file_start( pFileName );
[ # # ]
640 [ - + ][ + - ]: 25 : if( ! file_start )
641 : 0 : return NULL;
642 [ + - ]: 25 : file_iterator<> file_end = file_start.make_end();
643 [ + - ]: 25 : PDFGrammar< file_iterator<> > aGrammar( file_start );
644 : :
645 : : try
646 : : {
647 : : #if OSL_DEBUG_LEVEL > 1
648 : : boost::spirit::parse_info< file_iterator<> > aInfo =
649 : : #endif
650 : : boost::spirit::parse( file_start,
651 : : file_end,
652 : : aGrammar,
653 [ + - ][ + - ]: 25 : boost::spirit::space_p );
654 : : #if OSL_DEBUG_LEVEL > 1
655 : : fprintf( stderr, "parseinfo: stop at offset = %ld, hit = %s, full = %s, length = %lu\n",
656 : : aInfo.stop - file_start,
657 : : aInfo.hit ? "true" : "false",
658 : : aInfo.full ? "true" : "false",
659 : : aInfo.length );
660 : : #endif
661 : : }
662 : 0 : catch( const parser_error< const char*, file_iterator<> >& rError )
663 : : {
664 : : #if OSL_DEBUG_LEVEL > 1
665 : : fprintf( stderr, "parse error: %s at buffer pos %lu\nobject stack:\n",
666 : : rError.descriptor, rError.where - file_start );
667 : : size_t nElem = aGrammar.m_aObjectStack.size();
668 : : for( size_t i = 0; i < nElem; ++i )
669 : : {
670 : : fprintf( stderr, " %s\n", typeid( *(aGrammar.m_aObjectStack[i]) ).name() );
671 : : }
672 : : #endif
673 : : }
674 : :
675 : 25 : PDFEntry* pRet = NULL;
676 : 25 : unsigned int nEntries = aGrammar.m_aObjectStack.size();
677 [ + + ]: 25 : if( nEntries == 1 )
678 : : {
679 [ + - ]: 15 : pRet = aGrammar.m_aObjectStack.back();
680 [ + - ]: 15 : aGrammar.m_aObjectStack.pop_back();
681 : : }
682 : : #if OSL_DEBUG_LEVEL > 1
683 : : else if( nEntries > 1 )
684 : : {
685 : : fprintf( stderr, "error got %u stack objects in parse\n", nEntries );
686 : : for( unsigned int i = 0; i < nEntries; i++ )
687 : : {
688 : : fprintf( stderr, "%s\n", typeid(*aGrammar.m_aObjectStack[i]).name() );
689 : : PDFObject* pObj = dynamic_cast<PDFObject*>(aGrammar.m_aObjectStack[i]);
690 : : if( pObj )
691 : : fprintf( stderr, " -> object %d generation %d\n", pObj->m_nNumber, pObj->m_nGeneration );
692 : : else
693 : : fprintf( stderr, "(type %s)\n", typeid(*aGrammar.m_aObjectStack[i]).name() );
694 : : }
695 : : }
696 : : #endif
697 [ + - ][ + - ]: 25 : return pRet;
[ + - ]
698 : : #endif // WIN32
699 [ + - ][ + - ]: 33 : }
700 : :
701 : : #if defined __SUNPRO_CC
702 : : #pragma enable_warn
703 : : #elif defined _MSC_VER
704 : : #pragma warning(pop)
705 : : #endif
706 : :
707 : :
708 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|