/src/libreoffice/sdext/source/pdfimport/pdfparse/pdfentries.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | |
21 | | #include <pdfparse.hxx> |
22 | | |
23 | | #include <comphelper/hash.hxx> |
24 | | |
25 | | #include <o3tl/numeric.hxx> |
26 | | #include <rtl/strbuf.hxx> |
27 | | #include <rtl/ustring.hxx> |
28 | | #include <rtl/ustrbuf.hxx> |
29 | | #include <rtl/digest.h> |
30 | | #include <rtl/cipher.h> |
31 | | #include <sal/log.hxx> |
32 | | |
33 | | #include <zlib.h> |
34 | | |
35 | | #include <math.h> |
36 | | #include <map> |
37 | | |
38 | | #include <string.h> |
39 | | |
40 | | |
41 | | namespace pdfparse |
42 | | { |
43 | | |
44 | | struct EmitImplData |
45 | | { |
46 | | // xref table: maps object number to a pair of (generation, buffer offset) |
47 | | typedef std::map< unsigned int, std::pair< unsigned int, unsigned int > > XRefTable; |
48 | | XRefTable m_aXRefTable; |
49 | | // container of all indirect objects (usually a PDFFile*) |
50 | | const PDFContainer* m_pObjectContainer; |
51 | | unsigned int m_nDecryptObject; |
52 | | unsigned int m_nDecryptGeneration; |
53 | | |
54 | | // returns true if the xref table was updated |
55 | | bool insertXref( unsigned int nObject, unsigned int nGeneration, unsigned int nOffset ) |
56 | 0 | { |
57 | 0 | XRefTable::iterator it = m_aXRefTable.find( nObject ); |
58 | 0 | if( it == m_aXRefTable.end() ) |
59 | 0 | { |
60 | | // new entry |
61 | 0 | m_aXRefTable[ nObject ] = std::pair<unsigned int, unsigned int>(nGeneration,nOffset); |
62 | 0 | return true; |
63 | 0 | } |
64 | | // update old entry, if generation number is higher |
65 | 0 | if( it->second.first < nGeneration ) |
66 | 0 | { |
67 | 0 | it->second = std::pair<unsigned int, unsigned int>(nGeneration,nOffset); |
68 | 0 | return true; |
69 | 0 | } |
70 | 0 | return false; |
71 | 0 | } |
72 | | |
73 | | explicit EmitImplData( const PDFContainer* pTopContainer ) : |
74 | 0 | m_pObjectContainer( pTopContainer ), |
75 | 0 | m_nDecryptObject( 0 ), |
76 | 0 | m_nDecryptGeneration( 0 ) |
77 | 0 | {} |
78 | | void decrypt( const sal_uInt8* pInBuffer, sal_uInt32 nLen, sal_uInt8* pOutBuffer, |
79 | | unsigned int nObject, unsigned int nGeneration ) const |
80 | 0 | { |
81 | 0 | const PDFFile* pFile = dynamic_cast<const PDFFile*>(m_pObjectContainer); |
82 | 0 | pFile && pFile->decrypt( pInBuffer, nLen, pOutBuffer, nObject, nGeneration ); |
83 | 0 | } |
84 | | |
85 | | void setDecryptObject( unsigned int nObject, unsigned int nGeneration ) |
86 | 0 | { |
87 | 0 | m_nDecryptObject = nObject; |
88 | 0 | m_nDecryptGeneration = nGeneration; |
89 | 0 | } |
90 | | }; |
91 | | |
92 | | } |
93 | | |
94 | | using namespace pdfparse; |
95 | | |
96 | | EmitContext::EmitContext( const PDFContainer* pTop ) : |
97 | 0 | m_bDeflate( false ), |
98 | 0 | m_bDecrypt( false ) |
99 | 0 | { |
100 | 0 | if( pTop ) |
101 | 0 | m_pImplData.reset( new EmitImplData( pTop ) ); |
102 | 0 | } |
103 | | |
104 | | EmitContext::~EmitContext() |
105 | 0 | { |
106 | 0 | } |
107 | | |
108 | | PDFEntry::~PDFEntry() |
109 | 0 | { |
110 | 0 | } |
111 | | |
112 | | EmitImplData* PDFEntry::getEmitData( EmitContext const & rContext ) |
113 | 0 | { |
114 | 0 | return rContext.m_pImplData.get(); |
115 | 0 | } |
116 | | |
117 | | void PDFEntry::setEmitData( EmitContext& rContext, EmitImplData* pNewEmitData ) |
118 | 0 | { |
119 | 0 | if( rContext.m_pImplData && rContext.m_pImplData.get() != pNewEmitData ) |
120 | 0 | rContext.m_pImplData.reset(); |
121 | 0 | rContext.m_pImplData.reset( pNewEmitData ); |
122 | 0 | } |
123 | | |
124 | | PDFValue::~PDFValue() |
125 | | { |
126 | | } |
127 | | |
128 | | PDFComment::~PDFComment() |
129 | 0 | { |
130 | 0 | } |
131 | | |
132 | | bool PDFComment::emit( EmitContext& rWriteContext ) const |
133 | 0 | { |
134 | 0 | return rWriteContext.write( m_aComment.getStr(), m_aComment.getLength() ); |
135 | 0 | } |
136 | | |
137 | | PDFEntry* PDFComment::clone() const |
138 | 0 | { |
139 | 0 | return new PDFComment( m_aComment ); |
140 | 0 | } |
141 | | |
142 | | PDFName::~PDFName() |
143 | 0 | { |
144 | 0 | } |
145 | | |
146 | | bool PDFName::emit( EmitContext& rWriteContext ) const |
147 | 0 | { |
148 | 0 | if( ! rWriteContext.write( " /", 2 ) ) |
149 | 0 | return false; |
150 | 0 | return rWriteContext.write( m_aName.getStr(), m_aName.getLength() ); |
151 | 0 | } |
152 | | |
153 | | PDFEntry* PDFName::clone() const |
154 | 0 | { |
155 | 0 | return new PDFName( m_aName ); |
156 | 0 | } |
157 | | |
158 | | OUString PDFName::getFilteredName() const |
159 | 0 | { |
160 | 0 | OStringBuffer aFilter( m_aName.getLength() ); |
161 | 0 | const char* pStr = m_aName.getStr(); |
162 | 0 | unsigned int nLen = m_aName.getLength(); |
163 | 0 | for( unsigned int i = 0; i < nLen; i++ ) |
164 | 0 | { |
165 | 0 | if( (i + 2 < nLen) && pStr[i] == '#' ) |
166 | 0 | { |
167 | 0 | aFilter.append(o3tl::convertToHex<char, 0>(pStr[i + 1], pStr[i + 2])); |
168 | 0 | i += 2; |
169 | 0 | } |
170 | 0 | else |
171 | 0 | aFilter.append( pStr[i] ); |
172 | 0 | } |
173 | 0 | return OStringToOUString( aFilter, RTL_TEXTENCODING_UTF8 ); |
174 | 0 | } |
175 | | |
176 | | PDFString::~PDFString() |
177 | 0 | { |
178 | 0 | } |
179 | | |
180 | | bool PDFString::emit( EmitContext& rWriteContext ) const |
181 | 0 | { |
182 | 0 | if( ! rWriteContext.write( " ", 1 ) ) |
183 | 0 | return false; |
184 | 0 | EmitImplData* pEData = getEmitData( rWriteContext ); |
185 | 0 | if( rWriteContext.m_bDecrypt && pEData && pEData->m_nDecryptObject ) |
186 | 0 | { |
187 | 0 | OString aFiltered( getFilteredString() ); |
188 | | // decrypt inplace (evil since OString is supposed to be const |
189 | | // however in this case we know that getFilteredString returned a singular string instance |
190 | 0 | pEData->decrypt( reinterpret_cast<sal_uInt8 const *>(aFiltered.getStr()), aFiltered.getLength(), |
191 | 0 | reinterpret_cast<sal_uInt8 *>(const_cast<char *>(aFiltered.getStr())), |
192 | 0 | pEData->m_nDecryptObject, pEData->m_nDecryptGeneration ); |
193 | | // check for string or hex string |
194 | 0 | const char* pStr = aFiltered.getStr(); |
195 | 0 | if( aFiltered.getLength() > 1 && |
196 | 0 | ( (static_cast<unsigned char>(pStr[0]) == 0xff && static_cast<unsigned char>(pStr[1]) == 0xfe) || |
197 | 0 | (static_cast<unsigned char>(pStr[0]) == 0xfe && static_cast<unsigned char>(pStr[1]) == 0xff) ) ) |
198 | 0 | { |
199 | 0 | static const char pHexTab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', |
200 | 0 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
201 | 0 | if( ! rWriteContext.write( "<", 1 ) ) |
202 | 0 | return false; |
203 | 0 | for( sal_Int32 i = 0; i < aFiltered.getLength(); i++ ) |
204 | 0 | { |
205 | 0 | if( ! rWriteContext.write( pHexTab + ((sal_uInt32(pStr[i]) >> 4) & 0x0f), 1 ) ) |
206 | 0 | return false; |
207 | 0 | if( ! rWriteContext.write( pHexTab + (sal_uInt32(pStr[i]) & 0x0f), 1 ) ) |
208 | 0 | return false; |
209 | 0 | } |
210 | 0 | if( ! rWriteContext.write( ">", 1 ) ) |
211 | 0 | return false; |
212 | 0 | } |
213 | 0 | else |
214 | 0 | { |
215 | 0 | if( ! rWriteContext.write( "(", 1 ) ) |
216 | 0 | return false; |
217 | 0 | if( ! rWriteContext.write( aFiltered.getStr(), aFiltered.getLength() ) ) |
218 | 0 | return false; |
219 | 0 | if( ! rWriteContext.write( ")", 1 ) ) |
220 | 0 | return false; |
221 | 0 | } |
222 | 0 | return true; |
223 | 0 | } |
224 | 0 | return rWriteContext.write( m_aString.getStr(), m_aString.getLength() ); |
225 | 0 | } |
226 | | |
227 | | PDFEntry* PDFString::clone() const |
228 | 0 | { |
229 | 0 | return new PDFString( m_aString ); |
230 | 0 | } |
231 | | |
232 | | OString PDFString::getFilteredString() const |
233 | 0 | { |
234 | 0 | int nLen = m_aString.getLength(); |
235 | 0 | OStringBuffer aBuf( nLen ); |
236 | |
|
237 | 0 | const char* pStr = m_aString.getStr(); |
238 | 0 | if( *pStr == '(' ) |
239 | 0 | { |
240 | 0 | const char* pRun = pStr+1; |
241 | 0 | while( pRun - pStr < nLen-1 ) |
242 | 0 | { |
243 | 0 | if( *pRun == '\\' ) |
244 | 0 | { |
245 | 0 | pRun++; |
246 | 0 | if( pRun - pStr < nLen ) |
247 | 0 | { |
248 | 0 | char aEsc = 0; |
249 | 0 | if( *pRun == 'n' ) |
250 | 0 | aEsc = '\n'; |
251 | 0 | else if( *pRun == 'r' ) |
252 | 0 | aEsc = '\r'; |
253 | 0 | else if( *pRun == 't' ) |
254 | 0 | aEsc = '\t'; |
255 | 0 | else if( *pRun == 'b' ) |
256 | 0 | aEsc = '\b'; |
257 | 0 | else if( *pRun == 'f' ) |
258 | 0 | aEsc = '\f'; |
259 | 0 | else if( *pRun == '(' ) |
260 | 0 | aEsc = '('; |
261 | 0 | else if( *pRun == ')' ) |
262 | 0 | aEsc = ')'; |
263 | 0 | else if( *pRun == '\\' ) |
264 | 0 | aEsc = '\\'; |
265 | 0 | else if( *pRun == '\n' ) |
266 | 0 | { |
267 | 0 | pRun++; |
268 | 0 | continue; |
269 | 0 | } |
270 | 0 | else if( *pRun == '\r' ) |
271 | 0 | { |
272 | 0 | pRun++; |
273 | 0 | if( *pRun == '\n' ) |
274 | 0 | pRun++; |
275 | 0 | continue; |
276 | 0 | } |
277 | 0 | else |
278 | 0 | { |
279 | 0 | int i = 0; |
280 | 0 | while( i++ < 3 && *pRun >= '0' && *pRun <= '7' ) |
281 | 0 | aEsc = 8*aEsc + (*pRun++ - '0'); |
282 | | // move pointer back to last character of octal sequence |
283 | 0 | pRun--; |
284 | 0 | } |
285 | 0 | aBuf.append( aEsc ); |
286 | 0 | } |
287 | 0 | } |
288 | 0 | else |
289 | 0 | aBuf.append( *pRun ); |
290 | | // move pointer to next character |
291 | 0 | pRun++; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | else if( *pStr == '<' ) |
295 | 0 | { |
296 | 0 | const char* pRun = pStr+1; |
297 | 0 | while( *pRun != '>' && pRun - pStr < nLen ) |
298 | 0 | { |
299 | 0 | char rResult = 0; |
300 | 0 | if( *pRun >= '0' && *pRun <= '9' ) |
301 | 0 | rResult = char( ( *pRun-'0' ) << 4 ); |
302 | 0 | else if( *pRun >= 'a' && *pRun <= 'f' ) |
303 | 0 | rResult = char( ( *pRun-'a' + 10 ) << 4 ); |
304 | 0 | else if( *pRun >= 'A' && *pRun <= 'F' ) |
305 | 0 | rResult = char( ( *pRun-'A' + 10 ) << 4 ); |
306 | 0 | pRun++; |
307 | 0 | if( *pRun != '>' && pRun - pStr < nLen ) |
308 | 0 | { |
309 | 0 | if( *pRun >= '0' && *pRun <= '9' ) |
310 | 0 | rResult |= char( *pRun-'0' ); |
311 | 0 | else if( *pRun >= 'a' && *pRun <= 'f' ) |
312 | 0 | rResult |= char( *pRun-'a' + 10 ); |
313 | 0 | else if( *pRun >= 'A' && *pRun <= 'F' ) |
314 | 0 | rResult |= char( *pRun-'A' + 10 ); |
315 | 0 | } |
316 | 0 | pRun++; |
317 | 0 | aBuf.append( rResult ); |
318 | 0 | } |
319 | 0 | } |
320 | |
|
321 | 0 | return aBuf.makeStringAndClear(); |
322 | 0 | } |
323 | | |
324 | | PDFNumber::~PDFNumber() |
325 | | { |
326 | | } |
327 | | |
328 | | bool PDFNumber::emit( EmitContext& rWriteContext ) const |
329 | 0 | { |
330 | 0 | OStringBuffer aBuf( 32 ); |
331 | 0 | aBuf.append( ' ' ); |
332 | |
|
333 | 0 | double fValue = m_fValue; |
334 | 0 | bool bNeg = false; |
335 | 0 | int nPrecision = 5; |
336 | 0 | if( fValue < 0.0 ) |
337 | 0 | { |
338 | 0 | bNeg = true; |
339 | 0 | fValue=-fValue; |
340 | 0 | } |
341 | |
|
342 | 0 | sal_Int64 nInt = static_cast<sal_Int64>(fValue); |
343 | 0 | fValue -= static_cast<double>(nInt); |
344 | | // optimizing hardware may lead to a value of 1.0 after the subtraction |
345 | 0 | if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision ) |
346 | 0 | { |
347 | 0 | nInt++; |
348 | 0 | fValue = 0.0; |
349 | 0 | } |
350 | 0 | sal_Int64 nFrac = 0; |
351 | 0 | if( fValue ) |
352 | 0 | { |
353 | 0 | fValue *= pow( 10.0, static_cast<double>(nPrecision) ); |
354 | 0 | nFrac = static_cast<sal_Int64>(fValue); |
355 | 0 | } |
356 | 0 | if( bNeg && ( nInt || nFrac ) ) |
357 | 0 | aBuf.append( '-' ); |
358 | 0 | aBuf.append( nInt ); |
359 | 0 | if( nFrac ) |
360 | 0 | { |
361 | 0 | int i; |
362 | 0 | aBuf.append( '.' ); |
363 | 0 | sal_Int64 nBound = static_cast<sal_Int64>(pow( 10.0, nPrecision - 1.0 )+0.5); |
364 | 0 | for ( i = 0; ( i < nPrecision ) && nFrac; i++ ) |
365 | 0 | { |
366 | 0 | sal_Int64 nNumb = nFrac / nBound; |
367 | 0 | nFrac -= nNumb * nBound; |
368 | 0 | aBuf.append( nNumb ); |
369 | 0 | nBound /= 10; |
370 | 0 | } |
371 | 0 | } |
372 | |
|
373 | 0 | return rWriteContext.write( aBuf.getStr(), aBuf.getLength() ); |
374 | 0 | } |
375 | | |
376 | | PDFEntry* PDFNumber::clone() const |
377 | 0 | { |
378 | 0 | return new PDFNumber( m_fValue ); |
379 | 0 | } |
380 | | |
381 | | |
382 | | PDFBool::~PDFBool() |
383 | | { |
384 | | } |
385 | | |
386 | | bool PDFBool::emit( EmitContext& rWriteContext ) const |
387 | 0 | { |
388 | 0 | return m_bValue ? rWriteContext.write( " true", 5 ) : rWriteContext.write( " false", 6 ); |
389 | 0 | } |
390 | | |
391 | | PDFEntry* PDFBool::clone() const |
392 | 0 | { |
393 | 0 | return new PDFBool( m_bValue ); |
394 | 0 | } |
395 | | |
396 | | PDFNull::~PDFNull() |
397 | | { |
398 | | } |
399 | | |
400 | | bool PDFNull::emit( EmitContext& rWriteContext ) const |
401 | 0 | { |
402 | 0 | return rWriteContext.write( " null", 5 ); |
403 | 0 | } |
404 | | |
405 | | PDFEntry* PDFNull::clone() const |
406 | 0 | { |
407 | 0 | return new PDFNull(); |
408 | 0 | } |
409 | | |
410 | | |
411 | | PDFObjectRef::~PDFObjectRef() |
412 | | { |
413 | | } |
414 | | |
415 | | bool PDFObjectRef::emit( EmitContext& rWriteContext ) const |
416 | 0 | { |
417 | 0 | OString aBuf = |
418 | 0 | " " + |
419 | 0 | OString::number( sal_Int32( m_nNumber ) ) + |
420 | 0 | " " + |
421 | 0 | OString::number( sal_Int32( m_nGeneration ) ) + |
422 | 0 | " R"; |
423 | 0 | return rWriteContext.write( aBuf.getStr(), aBuf.getLength() ); |
424 | 0 | } |
425 | | |
426 | | PDFEntry* PDFObjectRef::clone() const |
427 | 0 | { |
428 | 0 | return new PDFObjectRef( m_nNumber, m_nGeneration ); |
429 | 0 | } |
430 | | |
431 | | PDFContainer::~PDFContainer() |
432 | 0 | { |
433 | 0 | } |
434 | | |
435 | | bool PDFContainer::emitSubElements( EmitContext& rWriteContext ) const |
436 | 0 | { |
437 | 0 | int nEle = m_aSubElements.size(); |
438 | 0 | for( int i = 0; i < nEle; i++ ) |
439 | 0 | { |
440 | 0 | if( rWriteContext.m_bDecrypt ) |
441 | 0 | { |
442 | 0 | const PDFName* pName = dynamic_cast<PDFName*>(m_aSubElements[i].get()); |
443 | 0 | if (pName && pName->m_aName == "Encrypt") |
444 | 0 | { |
445 | 0 | i++; |
446 | 0 | continue; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | if( ! m_aSubElements[i]->emit( rWriteContext ) ) |
450 | 0 | return false; |
451 | 0 | } |
452 | 0 | return true; |
453 | 0 | } |
454 | | |
455 | | void PDFContainer::cloneSubElements( std::vector<std::unique_ptr<PDFEntry>>& rNewSubElements ) const |
456 | 0 | { |
457 | 0 | int nEle = m_aSubElements.size(); |
458 | 0 | for( int i = 0; i < nEle; i++ ) |
459 | 0 | rNewSubElements.emplace_back( m_aSubElements[i]->clone() ); |
460 | 0 | } |
461 | | |
462 | | PDFObject* PDFContainer::findObject( unsigned int nNumber, unsigned int nGeneration ) const |
463 | 0 | { |
464 | 0 | unsigned int nEle = m_aSubElements.size(); |
465 | 0 | for( unsigned int i = 0; i < nEle; i++ ) |
466 | 0 | { |
467 | 0 | PDFObject* pObject = dynamic_cast<PDFObject*>(m_aSubElements[i].get()); |
468 | 0 | if( pObject && |
469 | 0 | pObject->m_nNumber == nNumber && |
470 | 0 | pObject->m_nGeneration == nGeneration ) |
471 | 0 | { |
472 | 0 | return pObject; |
473 | 0 | } |
474 | 0 | } |
475 | 0 | return nullptr; |
476 | 0 | } |
477 | | |
478 | | PDFArray::~PDFArray() |
479 | | { |
480 | | } |
481 | | |
482 | | bool PDFArray::emit( EmitContext& rWriteContext ) const |
483 | 0 | { |
484 | 0 | if( ! rWriteContext.write( "[", 1 ) ) |
485 | 0 | return false; |
486 | 0 | if( ! emitSubElements( rWriteContext ) ) |
487 | 0 | return false; |
488 | 0 | return rWriteContext.write( "]", 1 ); |
489 | 0 | } |
490 | | |
491 | | PDFEntry* PDFArray::clone() const |
492 | 0 | { |
493 | 0 | PDFArray* pNewAr = new PDFArray(); |
494 | 0 | cloneSubElements( pNewAr->m_aSubElements ); |
495 | 0 | return pNewAr; |
496 | 0 | } |
497 | | |
498 | | PDFDict::~PDFDict() |
499 | 0 | { |
500 | 0 | } |
501 | | |
502 | | bool PDFDict::emit( EmitContext& rWriteContext ) const |
503 | 0 | { |
504 | 0 | if( ! rWriteContext.write( "<<\n", 3 ) ) |
505 | 0 | return false; |
506 | 0 | if( ! emitSubElements( rWriteContext ) ) |
507 | 0 | return false; |
508 | 0 | return rWriteContext.write( "\n>>\n", 4 ); |
509 | 0 | } |
510 | | |
511 | | void PDFDict::insertValue( const OString& rName, std::unique_ptr<PDFEntry> pValue ) |
512 | 0 | { |
513 | 0 | if( ! pValue ) |
514 | 0 | eraseValue( rName ); |
515 | |
|
516 | 0 | PDFEntry* pValueTmp = nullptr; |
517 | 0 | std::unordered_map<OString,PDFEntry*>::iterator it = m_aMap.find( rName ); |
518 | 0 | if( it == m_aMap.end() ) |
519 | 0 | { |
520 | | // new name/value, pair, append it |
521 | 0 | m_aSubElements.emplace_back(std::make_unique<PDFName>(rName)); |
522 | 0 | m_aSubElements.emplace_back( std::move(pValue) ); |
523 | 0 | pValueTmp = m_aSubElements.back().get(); |
524 | 0 | } |
525 | 0 | else |
526 | 0 | { |
527 | 0 | unsigned int nSub = m_aSubElements.size(); |
528 | 0 | for( unsigned int i = 0; i < nSub; i++ ) |
529 | 0 | if( m_aSubElements[i].get() == it->second ) |
530 | 0 | { |
531 | 0 | m_aSubElements[i] = std::move(pValue); |
532 | 0 | pValueTmp = m_aSubElements[i].get(); |
533 | 0 | break; |
534 | 0 | } |
535 | 0 | } |
536 | 0 | assert(pValueTmp); |
537 | 0 | m_aMap[ rName ] = pValueTmp; |
538 | 0 | } |
539 | | |
540 | | void PDFDict::eraseValue( std::string_view rName ) |
541 | 0 | { |
542 | 0 | unsigned int nEle = m_aSubElements.size(); |
543 | 0 | for( unsigned int i = 0; i < nEle; i++ ) |
544 | 0 | { |
545 | 0 | PDFName* pName = dynamic_cast<PDFName*>(m_aSubElements[i].get()); |
546 | 0 | if( pName && pName->m_aName == rName ) |
547 | 0 | { |
548 | 0 | for( unsigned int j = i+1; j < nEle; j++ ) |
549 | 0 | { |
550 | 0 | if( dynamic_cast<PDFComment*>(m_aSubElements[j].get()) == nullptr ) |
551 | 0 | { |
552 | | // remove and free subelements from vector |
553 | 0 | m_aSubElements.erase( m_aSubElements.begin()+j ); |
554 | 0 | m_aSubElements.erase( m_aSubElements.begin()+i ); |
555 | 0 | buildMap(); |
556 | 0 | return; |
557 | 0 | } |
558 | 0 | } |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } |
562 | | |
563 | | PDFEntry* PDFDict::buildMap() |
564 | 0 | { |
565 | | // clear map |
566 | 0 | m_aMap.clear(); |
567 | | // build map |
568 | 0 | unsigned int nEle = m_aSubElements.size(); |
569 | 0 | PDFName* pName = nullptr; |
570 | 0 | for( unsigned int i = 0; i < nEle; i++ ) |
571 | 0 | { |
572 | 0 | if( dynamic_cast<PDFComment*>(m_aSubElements[i].get()) == nullptr ) |
573 | 0 | { |
574 | 0 | if( pName ) |
575 | 0 | { |
576 | 0 | m_aMap[ pName->m_aName ] = m_aSubElements[i].get(); |
577 | 0 | pName = nullptr; |
578 | 0 | } |
579 | 0 | else if( (pName = dynamic_cast<PDFName*>(m_aSubElements[i].get())) == nullptr ) |
580 | 0 | return m_aSubElements[i].get(); |
581 | 0 | } |
582 | 0 | } |
583 | 0 | return pName; |
584 | 0 | } |
585 | | |
586 | | PDFEntry* PDFDict::clone() const |
587 | 0 | { |
588 | 0 | PDFDict* pNewDict = new PDFDict(); |
589 | 0 | cloneSubElements( pNewDict->m_aSubElements ); |
590 | 0 | pNewDict->buildMap(); |
591 | 0 | return pNewDict; |
592 | 0 | } |
593 | | |
594 | | PDFStream::~PDFStream() |
595 | | { |
596 | | } |
597 | | |
598 | | bool PDFStream::emit( EmitContext& rWriteContext ) const |
599 | 0 | { |
600 | 0 | return rWriteContext.copyOrigBytes( m_nBeginOffset, m_nEndOffset-m_nBeginOffset ); |
601 | 0 | } |
602 | | |
603 | | PDFEntry* PDFStream::clone() const |
604 | 0 | { |
605 | 0 | return new PDFStream( m_nBeginOffset, m_nEndOffset, nullptr ); |
606 | 0 | } |
607 | | |
608 | | unsigned int PDFStream::getDictLength( const PDFContainer* pContainer ) const |
609 | 0 | { |
610 | 0 | if( ! m_pDict ) |
611 | 0 | return 0; |
612 | | // find /Length entry, can either be a direct or indirect number object |
613 | 0 | std::unordered_map<OString,PDFEntry*>::const_iterator it = |
614 | 0 | m_pDict->m_aMap.find( "Length"_ostr ); |
615 | 0 | if( it == m_pDict->m_aMap.end() ) |
616 | 0 | return 0; |
617 | 0 | PDFNumber* pNum = dynamic_cast<PDFNumber*>(it->second); |
618 | 0 | if( ! pNum && pContainer ) |
619 | 0 | { |
620 | 0 | PDFObjectRef* pRef = dynamic_cast<PDFObjectRef*>(it->second); |
621 | 0 | if( pRef ) |
622 | 0 | { |
623 | 0 | int nEle = pContainer->m_aSubElements.size(); |
624 | 0 | for (int i = 0; i < nEle; i++) |
625 | 0 | { |
626 | 0 | PDFObject* pObj = dynamic_cast<PDFObject*>(pContainer->m_aSubElements[i].get()); |
627 | 0 | if( pObj && |
628 | 0 | pObj->m_nNumber == pRef->m_nNumber && |
629 | 0 | pObj->m_nGeneration == pRef->m_nGeneration ) |
630 | 0 | { |
631 | 0 | if( pObj->m_pObject ) |
632 | 0 | pNum = dynamic_cast<PDFNumber*>(pObj->m_pObject); |
633 | 0 | break; |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } |
637 | 0 | } |
638 | 0 | return pNum ? static_cast<unsigned int>(pNum->m_fValue) : 0; |
639 | 0 | } |
640 | | |
641 | | PDFObject::~PDFObject() |
642 | | { |
643 | | } |
644 | | |
645 | | bool PDFObject::getDeflatedStream( std::unique_ptr<char[]>& rpStream, unsigned int* pBytes, const PDFContainer* pObjectContainer, EmitContext& rContext ) const |
646 | 0 | { |
647 | 0 | bool bIsDeflated = false; |
648 | 0 | if( m_pStream && m_pStream->m_pDict && |
649 | 0 | m_pStream->m_nEndOffset > m_pStream->m_nBeginOffset+15 |
650 | 0 | ) |
651 | 0 | { |
652 | 0 | unsigned int nOuterStreamLen = m_pStream->m_nEndOffset - m_pStream->m_nBeginOffset; |
653 | 0 | rpStream.reset(new char[ nOuterStreamLen ]); |
654 | 0 | unsigned int nRead = rContext.readOrigBytes( m_pStream->m_nBeginOffset, nOuterStreamLen, rpStream.get() ); |
655 | 0 | if( nRead != nOuterStreamLen ) |
656 | 0 | { |
657 | 0 | rpStream.reset(); |
658 | 0 | *pBytes = 0; |
659 | 0 | return false; |
660 | 0 | } |
661 | | // is there a filter entry ? |
662 | 0 | std::unordered_map<OString,PDFEntry*>::const_iterator it = |
663 | 0 | m_pStream->m_pDict->m_aMap.find( "Filter"_ostr ); |
664 | 0 | if( it != m_pStream->m_pDict->m_aMap.end() ) |
665 | 0 | { |
666 | 0 | PDFName* pFilter = dynamic_cast<PDFName*>(it->second); |
667 | 0 | if( ! pFilter ) |
668 | 0 | { |
669 | 0 | PDFArray* pArray = dynamic_cast<PDFArray*>(it->second); |
670 | 0 | if( pArray && ! pArray->m_aSubElements.empty() ) |
671 | 0 | { |
672 | 0 | pFilter = dynamic_cast<PDFName*>(pArray->m_aSubElements.front().get()); |
673 | 0 | } |
674 | 0 | } |
675 | | |
676 | | // is the (first) filter FlateDecode ? |
677 | 0 | if (pFilter && pFilter->m_aName == "FlateDecode") |
678 | 0 | { |
679 | 0 | bIsDeflated = true; |
680 | 0 | } |
681 | 0 | } |
682 | | // prepare compressed data section |
683 | 0 | char* pStream = rpStream.get(); |
684 | 0 | if( pStream[0] == 's' ) |
685 | 0 | pStream += 6; // skip "stream" |
686 | | // "stream" is followed by CR LF or by LF alone, and the data starts after that |
687 | 0 | if( *pStream == '\r' ) |
688 | 0 | pStream++; |
689 | 0 | if( *pStream == '\n' ) |
690 | 0 | pStream++; |
691 | | // get the compressed length |
692 | 0 | *pBytes = m_pStream->getDictLength( pObjectContainer ); |
693 | 0 | unsigned int nAvailable = nOuterStreamLen - static_cast<unsigned int>(pStream - rpStream.get()); |
694 | 0 | if (*pBytes > nAvailable) |
695 | 0 | { |
696 | 0 | SAL_WARN("sdext.pdfimport.pdfparse", "stream /Length " << *pBytes << " exceeds " << nAvailable << " available bytes"); |
697 | 0 | *pBytes = nAvailable; |
698 | 0 | } |
699 | 0 | if( pStream != rpStream.get() ) |
700 | 0 | memmove( rpStream.get(), pStream, *pBytes ); |
701 | 0 | if( rContext.m_bDecrypt ) |
702 | 0 | { |
703 | 0 | EmitImplData* pEData = getEmitData( rContext ); |
704 | 0 | pEData->decrypt( reinterpret_cast<const sal_uInt8*>(rpStream.get()), |
705 | 0 | *pBytes, |
706 | 0 | reinterpret_cast<sal_uInt8*>(rpStream.get()), |
707 | 0 | m_nNumber, |
708 | 0 | m_nGeneration |
709 | 0 | ); // decrypt inplace |
710 | 0 | } |
711 | 0 | } |
712 | 0 | else |
713 | 0 | { |
714 | 0 | *pBytes = 0; |
715 | 0 | } |
716 | 0 | return bIsDeflated; |
717 | 0 | } |
718 | | |
719 | | static void unzipToBuffer( char* pBegin, unsigned int nLen, |
720 | | sal_uInt8** pOutBuf, sal_uInt32* pOutLen ) |
721 | 0 | { |
722 | 0 | z_stream aZStr; |
723 | 0 | aZStr.next_in = reinterpret_cast<Bytef *>(pBegin); |
724 | 0 | aZStr.avail_in = nLen; |
725 | 0 | aZStr.total_out = aZStr.total_in = 0; |
726 | 0 | aZStr.zalloc = nullptr; |
727 | 0 | aZStr.zfree = nullptr; |
728 | 0 | aZStr.opaque = nullptr; |
729 | |
|
730 | 0 | int err = inflateInit(&aZStr); |
731 | |
|
732 | 0 | const unsigned int buf_increment_size = 16384; |
733 | |
|
734 | 0 | if (auto p = static_cast<sal_uInt8*>(std::realloc(*pOutBuf, buf_increment_size))) |
735 | 0 | { |
736 | 0 | *pOutBuf = p; |
737 | 0 | aZStr.next_out = reinterpret_cast<Bytef*>(*pOutBuf); |
738 | 0 | aZStr.avail_out = buf_increment_size; |
739 | 0 | *pOutLen = buf_increment_size; |
740 | 0 | } |
741 | 0 | else |
742 | 0 | err = Z_MEM_ERROR; |
743 | 0 | while( err != Z_STREAM_END && err >= Z_OK && aZStr.avail_in ) |
744 | 0 | { |
745 | 0 | err = inflate( &aZStr, Z_NO_FLUSH ); |
746 | 0 | if( aZStr.avail_out == 0 ) |
747 | 0 | { |
748 | 0 | if( err != Z_STREAM_END ) |
749 | 0 | { |
750 | 0 | const int nNewAlloc = *pOutLen + buf_increment_size; |
751 | 0 | if (auto p = static_cast<sal_uInt8*>(std::realloc(*pOutBuf, nNewAlloc))) |
752 | 0 | { |
753 | 0 | *pOutBuf = p; |
754 | 0 | aZStr.next_out = reinterpret_cast<Bytef*>(*pOutBuf + *pOutLen); |
755 | 0 | aZStr.avail_out = buf_increment_size; |
756 | 0 | *pOutLen = nNewAlloc; |
757 | 0 | } |
758 | 0 | else |
759 | 0 | err = Z_MEM_ERROR; |
760 | 0 | } |
761 | 0 | } |
762 | 0 | } |
763 | 0 | if( err == Z_STREAM_END ) |
764 | 0 | { |
765 | 0 | if( aZStr.avail_out > 0 ) |
766 | 0 | *pOutLen -= aZStr.avail_out; |
767 | 0 | } |
768 | 0 | inflateEnd(&aZStr); |
769 | 0 | if( err < Z_OK ) |
770 | 0 | { |
771 | 0 | std::free( *pOutBuf ); |
772 | 0 | *pOutBuf = nullptr; |
773 | 0 | *pOutLen = 0; |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | void PDFObject::writeStream( EmitContext& rWriteContext, const PDFFile* pParsedFile ) const |
778 | 0 | { |
779 | 0 | if( !m_pStream ) |
780 | 0 | return; |
781 | | |
782 | 0 | std::unique_ptr<char[]> pStream; |
783 | 0 | unsigned int nBytes = 0; |
784 | 0 | if( getDeflatedStream( pStream, &nBytes, pParsedFile, rWriteContext ) && nBytes && rWriteContext.m_bDeflate ) |
785 | 0 | { |
786 | 0 | sal_uInt8* pOutBytes = nullptr; |
787 | 0 | sal_uInt32 nOutBytes = 0; |
788 | 0 | unzipToBuffer( pStream.get(), nBytes, &pOutBytes, &nOutBytes ); |
789 | 0 | rWriteContext.write( pOutBytes, nOutBytes ); |
790 | 0 | std::free( pOutBytes ); |
791 | 0 | } |
792 | 0 | else if( pStream && nBytes ) |
793 | 0 | rWriteContext.write( pStream.get(), nBytes ); |
794 | 0 | } |
795 | | |
796 | | bool PDFObject::emit( EmitContext& rWriteContext ) const |
797 | 0 | { |
798 | 0 | if( ! rWriteContext.write( "\n", 1 ) ) |
799 | 0 | return false; |
800 | | |
801 | 0 | EmitImplData* pEData = getEmitData( rWriteContext ); |
802 | 0 | if( pEData ) |
803 | 0 | pEData->insertXref( m_nNumber, m_nGeneration, rWriteContext.getCurPos() ); |
804 | |
|
805 | 0 | OString aBuf = |
806 | 0 | OString::number( sal_Int32( m_nNumber ) ) + |
807 | 0 | " " + |
808 | 0 | OString::number( sal_Int32( m_nGeneration ) ) + |
809 | 0 | " obj\n"; |
810 | 0 | if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) ) |
811 | 0 | return false; |
812 | | |
813 | 0 | if( pEData ) |
814 | 0 | pEData->setDecryptObject( m_nNumber, m_nGeneration ); |
815 | 0 | if( (rWriteContext.m_bDeflate || rWriteContext.m_bDecrypt) && pEData ) |
816 | 0 | { |
817 | 0 | std::unique_ptr<char[]> pStream; |
818 | 0 | unsigned int nBytes = 0; |
819 | 0 | bool bDeflate = getDeflatedStream( pStream, &nBytes, pEData->m_pObjectContainer, rWriteContext ); |
820 | 0 | if( pStream && nBytes ) |
821 | 0 | { |
822 | | // unzip the stream |
823 | 0 | sal_uInt8* pOutBytes = nullptr; |
824 | 0 | sal_uInt32 nOutBytes = 0; |
825 | 0 | if( bDeflate && rWriteContext.m_bDeflate ) |
826 | 0 | unzipToBuffer( pStream.get(), nBytes, &pOutBytes, &nOutBytes ); |
827 | 0 | else |
828 | 0 | { |
829 | | // nothing to deflate, but decryption has happened |
830 | 0 | pOutBytes = reinterpret_cast<sal_uInt8*>(pStream.get()); |
831 | 0 | nOutBytes = static_cast<sal_uInt32>(nBytes); |
832 | 0 | } |
833 | |
|
834 | 0 | if( nOutBytes ) |
835 | 0 | { |
836 | | // clone this object |
837 | 0 | std::unique_ptr<PDFObject> pClone(static_cast<PDFObject*>(clone())); |
838 | | // set length in the dictionary to new stream length |
839 | 0 | std::unique_ptr<PDFNumber> pNewLen(new PDFNumber( double(nOutBytes) )); |
840 | 0 | pClone->m_pStream->m_pDict->insertValue( "Length"_ostr, std::move(pNewLen) ); |
841 | |
|
842 | 0 | if( bDeflate && rWriteContext.m_bDeflate ) |
843 | 0 | { |
844 | | // delete flatedecode filter |
845 | 0 | std::unordered_map<OString,PDFEntry*>::const_iterator it = |
846 | 0 | pClone->m_pStream->m_pDict->m_aMap.find( "Filter"_ostr ); |
847 | 0 | if( it != pClone->m_pStream->m_pDict->m_aMap.end() ) |
848 | 0 | { |
849 | 0 | PDFName* pFilter = dynamic_cast<PDFName*>(it->second); |
850 | 0 | if (pFilter && pFilter->m_aName == "FlateDecode") |
851 | 0 | pClone->m_pStream->m_pDict->eraseValue( "Filter" ); |
852 | 0 | else |
853 | 0 | { |
854 | 0 | PDFArray* pArray = dynamic_cast<PDFArray*>(it->second); |
855 | 0 | if( pArray && ! pArray->m_aSubElements.empty() ) |
856 | 0 | { |
857 | 0 | pFilter = dynamic_cast<PDFName*>(pArray->m_aSubElements.front().get()); |
858 | 0 | if (pFilter && pFilter->m_aName == "FlateDecode") |
859 | 0 | { |
860 | 0 | pArray->m_aSubElements.erase( pArray->m_aSubElements.begin() ); |
861 | 0 | } |
862 | 0 | } |
863 | 0 | } |
864 | 0 | } |
865 | 0 | } |
866 | | |
867 | | // write sub elements except stream |
868 | 0 | bool bRet = true; |
869 | 0 | unsigned int nEle = pClone->m_aSubElements.size(); |
870 | 0 | for( unsigned int i = 0; i < nEle && bRet; i++ ) |
871 | 0 | { |
872 | 0 | if( pClone->m_aSubElements[i].get() != pClone->m_pStream ) |
873 | 0 | bRet = pClone->m_aSubElements[i]->emit( rWriteContext ); |
874 | 0 | } |
875 | 0 | pClone.reset(); |
876 | | // write stream |
877 | 0 | if( bRet ) |
878 | 0 | bRet = rWriteContext.write("stream\n", 7) |
879 | 0 | && rWriteContext.write(pOutBytes, nOutBytes) |
880 | 0 | && rWriteContext.write("\nendstream\nendobj\n", 18); |
881 | 0 | if( pOutBytes != reinterpret_cast<sal_uInt8*>(pStream.get()) ) |
882 | 0 | std::free( pOutBytes ); |
883 | 0 | pEData->setDecryptObject( 0, 0 ); |
884 | 0 | return bRet; |
885 | 0 | } |
886 | 0 | if( pOutBytes != reinterpret_cast<sal_uInt8*>(pStream.get()) ) |
887 | 0 | std::free( pOutBytes ); |
888 | 0 | } |
889 | 0 | } |
890 | | |
891 | 0 | bool bRet = emitSubElements( rWriteContext ) && |
892 | 0 | rWriteContext.write( "\nendobj\n", 8 ); |
893 | 0 | if( pEData ) |
894 | 0 | pEData->setDecryptObject( 0, 0 ); |
895 | 0 | return bRet; |
896 | 0 | } |
897 | | |
898 | | PDFEntry* PDFObject::clone() const |
899 | 0 | { |
900 | 0 | PDFObject* pNewOb = new PDFObject( m_nNumber, m_nGeneration ); |
901 | 0 | cloneSubElements( pNewOb->m_aSubElements ); |
902 | 0 | unsigned int nEle = m_aSubElements.size(); |
903 | 0 | for( unsigned int i = 0; i < nEle; i++ ) |
904 | 0 | { |
905 | 0 | if( m_aSubElements[i].get() == m_pObject ) |
906 | 0 | pNewOb->m_pObject = pNewOb->m_aSubElements[i].get(); |
907 | 0 | else if( m_aSubElements[i].get() == m_pStream && pNewOb->m_pObject ) |
908 | 0 | { |
909 | 0 | pNewOb->m_pStream = dynamic_cast<PDFStream*>(pNewOb->m_aSubElements[i].get()); |
910 | 0 | PDFDict* pNewDict = dynamic_cast<PDFDict*>(pNewOb->m_pObject); |
911 | 0 | if (pNewDict && pNewOb->m_pStream) |
912 | 0 | pNewOb->m_pStream->m_pDict = pNewDict; |
913 | 0 | } |
914 | 0 | } |
915 | 0 | return pNewOb; |
916 | 0 | } |
917 | | |
918 | | PDFTrailer::~PDFTrailer() |
919 | | { |
920 | | } |
921 | | |
922 | | bool PDFTrailer::emit( EmitContext& rWriteContext ) const |
923 | 0 | { |
924 | | // get xref offset |
925 | 0 | unsigned int nXRefPos = rWriteContext.getCurPos(); |
926 | | // begin xref section, object 0 is always free |
927 | 0 | if( ! rWriteContext.write( "xref\r\n" |
928 | 0 | "0 1\r\n" |
929 | 0 | "0000000000 65535 f\r\n", 31 ) ) |
930 | 0 | return false; |
931 | | // check if we are emitting a complete PDF file |
932 | 0 | EmitImplData* pEData = getEmitData( rWriteContext ); |
933 | 0 | if( pEData ) |
934 | 0 | { |
935 | | // emit object xrefs |
936 | 0 | const EmitImplData::XRefTable& rXRefs = pEData->m_aXRefTable; |
937 | 0 | EmitImplData::XRefTable::const_iterator section_begin, section_end; |
938 | 0 | section_begin = rXRefs.begin(); |
939 | 0 | while( section_begin != rXRefs.end() ) |
940 | 0 | { |
941 | | // find end of continuous object numbers |
942 | 0 | section_end = section_begin; |
943 | 0 | unsigned int nLast = section_begin->first; |
944 | 0 | while( (++section_end) != rXRefs.end() && |
945 | 0 | section_end->first == nLast+1 ) |
946 | 0 | nLast = section_end->first; |
947 | | // write first object number and number of following entries |
948 | 0 | OStringBuffer aBuf = |
949 | 0 | OString::number(sal_Int32( section_begin->first ) ) |
950 | 0 | + " " |
951 | 0 | + OString::number(sal_Int32(nLast - section_begin->first + 1)) |
952 | 0 | + "\r\n"; |
953 | 0 | if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) ) |
954 | 0 | return false; |
955 | 0 | while( section_begin != section_end ) |
956 | 0 | { |
957 | | // write 20 char entry of form |
958 | | // 0000offset 00gen n\r\n |
959 | 0 | aBuf.setLength( 0 ); |
960 | 0 | OString aOffset( OString::number( section_begin->second.second ) ); |
961 | 0 | int nPad = 10 - aOffset.getLength(); |
962 | 0 | for( int i = 0; i < nPad; i++ ) |
963 | 0 | aBuf.append( '0' ); |
964 | 0 | aBuf.append( aOffset + " " ); |
965 | 0 | OString aGeneration( OString::number( section_begin->second.first ) ); |
966 | 0 | nPad = 5 - aGeneration.getLength(); |
967 | 0 | for( int i = 0; i < nPad; i++ ) |
968 | 0 | aBuf.append( '0' ); |
969 | 0 | aBuf.append( aGeneration + " n\r\n" ); |
970 | 0 | if( ! rWriteContext.write( aBuf.getStr(), 20 ) ) |
971 | 0 | return false; |
972 | 0 | ++section_begin; |
973 | 0 | } |
974 | 0 | } |
975 | 0 | } |
976 | 0 | if( ! rWriteContext.write( "trailer\n", 8 ) ) |
977 | 0 | return false; |
978 | 0 | if( ! emitSubElements( rWriteContext ) ) |
979 | 0 | return false; |
980 | 0 | if( ! rWriteContext.write( "startxref\n", 10 ) ) |
981 | 0 | return false; |
982 | 0 | OString aOffset( OString::number( nXRefPos ) ); |
983 | 0 | if( ! rWriteContext.write( aOffset.getStr(), aOffset.getLength() ) ) |
984 | 0 | return false; |
985 | 0 | return rWriteContext.write( "\n%%EOF\n", 7 ); |
986 | 0 | } |
987 | | |
988 | | PDFEntry* PDFTrailer::clone() const |
989 | 0 | { |
990 | 0 | PDFTrailer* pNewTr = new PDFTrailer(); |
991 | 0 | cloneSubElements( pNewTr->m_aSubElements ); |
992 | 0 | unsigned int nEle = m_aSubElements.size(); |
993 | 0 | for( unsigned int i = 0; i < nEle; i++ ) |
994 | 0 | { |
995 | 0 | if( m_aSubElements[i].get() == m_pDict ) |
996 | 0 | { |
997 | 0 | pNewTr->m_pDict = dynamic_cast<PDFDict*>(pNewTr->m_aSubElements[i].get()); |
998 | 0 | break; |
999 | 0 | } |
1000 | 0 | } |
1001 | 0 | return pNewTr; |
1002 | 0 | } |
1003 | | |
1004 | 0 | #define ENCRYPTION_KEY_LEN 16 |
1005 | | #define ENCRYPTION_BUF_LEN 32 |
1006 | | |
1007 | | namespace pdfparse { |
1008 | | struct PDFFileImplData |
1009 | | { |
1010 | | bool m_bIsEncrypted; |
1011 | | bool m_bStandardHandler; |
1012 | | sal_uInt32 m_nAlgoVersion; |
1013 | | sal_uInt32 m_nStandardRevision; |
1014 | | sal_uInt32 m_nKeyLength; |
1015 | | sal_uInt8 m_aOEntry[32] = {}; |
1016 | | sal_uInt8 m_aUEntry[32] = {}; |
1017 | | sal_uInt32 m_nPEntry; |
1018 | | OString m_aDocID; |
1019 | | rtlCipher m_aCipher; |
1020 | | |
1021 | | sal_uInt8 m_aDecryptionKey[ENCRYPTION_KEY_LEN+5] = {}; // maximum handled key length |
1022 | | |
1023 | | PDFFileImplData() : |
1024 | 0 | m_bIsEncrypted( false ), |
1025 | 0 | m_bStandardHandler( false ), |
1026 | 0 | m_nAlgoVersion( 0 ), |
1027 | 0 | m_nStandardRevision( 0 ), |
1028 | 0 | m_nKeyLength( 0 ), |
1029 | 0 | m_nPEntry( 0 ), |
1030 | 0 | m_aCipher( nullptr ) |
1031 | 0 | { |
1032 | 0 | } |
1033 | | |
1034 | | ~PDFFileImplData() |
1035 | 0 | { |
1036 | 0 | if( m_aCipher ) |
1037 | 0 | rtl_cipher_destroyARCFOUR( m_aCipher ); |
1038 | 0 | } |
1039 | | }; |
1040 | | } |
1041 | | |
1042 | | PDFFile::PDFFile() |
1043 | 0 | : m_nMajor( 0 ), m_nMinor( 0 ) |
1044 | 0 | { |
1045 | 0 | } |
1046 | | |
1047 | | PDFFile::~PDFFile() |
1048 | 0 | { |
1049 | 0 | } |
1050 | | |
1051 | | bool PDFFile::isEncrypted() const |
1052 | 0 | { |
1053 | 0 | return impl_getData()->m_bIsEncrypted; |
1054 | 0 | } |
1055 | | |
1056 | | bool PDFFile::decrypt( const sal_uInt8* pInBuffer, sal_uInt32 nLen, sal_uInt8* pOutBuffer, |
1057 | | unsigned int nObject, unsigned int nGeneration ) const |
1058 | 0 | { |
1059 | 0 | if( ! isEncrypted() ) |
1060 | 0 | return false; |
1061 | | |
1062 | 0 | if( ! m_pData->m_aCipher ) |
1063 | 0 | m_pData->m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); |
1064 | | |
1065 | | // modify encryption key |
1066 | 0 | sal_uInt32 i = m_pData->m_nKeyLength; |
1067 | 0 | m_pData->m_aDecryptionKey[i++] = sal_uInt8(nObject&0xff); |
1068 | 0 | m_pData->m_aDecryptionKey[i++] = sal_uInt8((nObject>>8)&0xff); |
1069 | 0 | m_pData->m_aDecryptionKey[i++] = sal_uInt8((nObject>>16)&0xff); |
1070 | 0 | m_pData->m_aDecryptionKey[i++] = sal_uInt8(nGeneration&0xff); |
1071 | 0 | m_pData->m_aDecryptionKey[i++] = sal_uInt8((nGeneration>>8)&0xff); |
1072 | |
|
1073 | 0 | ::std::vector<unsigned char> const aSum(::comphelper::Hash::calculateHash( |
1074 | 0 | m_pData->m_aDecryptionKey, i, ::comphelper::HashType::MD5)); |
1075 | |
|
1076 | 0 | if( i > 16 ) |
1077 | 0 | i = 16; |
1078 | |
|
1079 | 0 | rtlCipherError aErr = rtl_cipher_initARCFOUR( m_pData->m_aCipher, |
1080 | 0 | rtl_Cipher_DirectionDecode, |
1081 | 0 | aSum.data(), i, |
1082 | 0 | nullptr, 0 ); |
1083 | 0 | if( aErr == rtl_Cipher_E_None ) |
1084 | 0 | aErr = rtl_cipher_decodeARCFOUR( m_pData->m_aCipher, |
1085 | 0 | pInBuffer, nLen, |
1086 | 0 | pOutBuffer, nLen ); |
1087 | 0 | return aErr == rtl_Cipher_E_None; |
1088 | 0 | } |
1089 | | |
1090 | | const sal_uInt8 nPadString[32] = |
1091 | | { |
1092 | | 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, |
1093 | | 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A |
1094 | | }; |
1095 | | |
1096 | | static void pad_or_truncate_to_32( const OString& rStr, char* pBuffer ) |
1097 | 0 | { |
1098 | 0 | int nLen = rStr.getLength(); |
1099 | 0 | if( nLen > 32 ) |
1100 | 0 | nLen = 32; |
1101 | 0 | const char* pStr = rStr.getStr(); |
1102 | 0 | memcpy( pBuffer, pStr, nLen ); |
1103 | 0 | int i = 0; |
1104 | 0 | while( nLen < 32 ) |
1105 | 0 | pBuffer[nLen++] = nPadString[i++]; |
1106 | 0 | } |
1107 | | |
1108 | | // pass at least pData->m_nKeyLength bytes in |
1109 | | static sal_uInt32 password_to_key( const OString& rPwd, sal_uInt8* pOutKey, PDFFileImplData const * pData, bool bComputeO ) |
1110 | 0 | { |
1111 | | // see PDF reference 1.4 Algorithm 3.2 |
1112 | | // encrypt pad string |
1113 | 0 | char aPadPwd[ENCRYPTION_BUF_LEN]; |
1114 | 0 | pad_or_truncate_to_32( rPwd, aPadPwd ); |
1115 | 0 | ::comphelper::Hash aDigest(::comphelper::HashType::MD5); |
1116 | 0 | aDigest.update(aPadPwd, sizeof(aPadPwd)); |
1117 | 0 | if( ! bComputeO ) |
1118 | 0 | { |
1119 | 0 | aDigest.update(pData->m_aOEntry, 32); |
1120 | 0 | sal_uInt8 aPEntry[4]; |
1121 | 0 | aPEntry[0] = static_cast<sal_uInt8>(pData->m_nPEntry & 0xff); |
1122 | 0 | aPEntry[1] = static_cast<sal_uInt8>((pData->m_nPEntry >> 8 ) & 0xff); |
1123 | 0 | aPEntry[2] = static_cast<sal_uInt8>((pData->m_nPEntry >> 16) & 0xff); |
1124 | 0 | aPEntry[3] = static_cast<sal_uInt8>((pData->m_nPEntry >> 24) & 0xff); |
1125 | 0 | aDigest.update(aPEntry, sizeof(aPEntry)); |
1126 | 0 | aDigest.update(pData->m_aDocID.getStr(), pData->m_aDocID.getLength()); |
1127 | 0 | } |
1128 | 0 | ::std::vector<unsigned char> nSum(aDigest.finalize()); |
1129 | 0 | if( pData->m_nStandardRevision == 3 ) |
1130 | 0 | { |
1131 | 0 | for( int i = 0; i < 50; i++ ) |
1132 | 0 | { |
1133 | 0 | nSum = ::comphelper::Hash::calculateHash(nSum.data(), nSum.size(), |
1134 | 0 | ::comphelper::HashType::MD5); |
1135 | 0 | } |
1136 | 0 | } |
1137 | 0 | sal_uInt32 nLen = pData->m_nKeyLength; |
1138 | 0 | if( nLen > RTL_DIGEST_LENGTH_MD5 ) |
1139 | 0 | nLen = RTL_DIGEST_LENGTH_MD5; |
1140 | 0 | memcpy( pOutKey, nSum.data(), nLen ); |
1141 | 0 | return nLen; |
1142 | 0 | } |
1143 | | |
1144 | | static bool check_user_password( const OString& rPwd, PDFFileImplData* pData ) |
1145 | 0 | { |
1146 | | // see PDF reference 1.4 Algorithm 3.6 |
1147 | 0 | bool bValid = false; |
1148 | 0 | sal_uInt8 aKey[ENCRYPTION_KEY_LEN]; |
1149 | 0 | sal_uInt32 nKeyLen = password_to_key( rPwd, aKey, pData, false ); |
1150 | | // save (at this time potential) decryption key for later use |
1151 | 0 | memcpy( pData->m_aDecryptionKey, aKey, nKeyLen ); |
1152 | 0 | if( pData->m_nStandardRevision == 2 ) |
1153 | 0 | { |
1154 | 0 | sal_uInt8 nEncryptedEntry[ENCRYPTION_BUF_LEN] = {}; |
1155 | | // see PDF reference 1.4 Algorithm 3.4 |
1156 | | // encrypt pad string |
1157 | 0 | if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode, |
1158 | 0 | aKey, nKeyLen, |
1159 | 0 | nullptr, 0 ) |
1160 | 0 | != rtl_Cipher_E_None) |
1161 | 0 | { |
1162 | 0 | return false; //TODO: differentiate "failed to decrypt" from "wrong password" |
1163 | 0 | } |
1164 | 0 | rtl_cipher_encodeARCFOUR( pData->m_aCipher, nPadString, sizeof( nPadString ), |
1165 | 0 | nEncryptedEntry, sizeof( nEncryptedEntry ) ); |
1166 | 0 | bValid = (memcmp( nEncryptedEntry, pData->m_aUEntry, 32 ) == 0); |
1167 | 0 | } |
1168 | 0 | else if( pData->m_nStandardRevision == 3 ) |
1169 | 0 | { |
1170 | | // see PDF reference 1.4 Algorithm 3.5 |
1171 | 0 | ::comphelper::Hash aDigest(::comphelper::HashType::MD5); |
1172 | 0 | aDigest.update(nPadString, sizeof(nPadString)); |
1173 | 0 | aDigest.update(pData->m_aDocID.getStr(), pData->m_aDocID.getLength()); |
1174 | 0 | ::std::vector<unsigned char> nEncryptedEntry(aDigest.finalize()); |
1175 | 0 | if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode, |
1176 | 0 | aKey, sizeof(aKey), nullptr, 0 ) |
1177 | 0 | != rtl_Cipher_E_None) |
1178 | 0 | { |
1179 | 0 | return false; //TODO: differentiate "failed to decrypt" from "wrong password" |
1180 | 0 | } |
1181 | 0 | rtl_cipher_encodeARCFOUR( pData->m_aCipher, |
1182 | 0 | nEncryptedEntry.data(), 16, |
1183 | 0 | nEncryptedEntry.data(), 16 ); // encrypt in place |
1184 | 0 | for( int i = 1; i <= 19; i++ ) // do it 19 times, start with 1 |
1185 | 0 | { |
1186 | 0 | sal_uInt8 aTempKey[ENCRYPTION_KEY_LEN]; |
1187 | 0 | for( size_t j = 0; j < sizeof(aTempKey); j++ ) |
1188 | 0 | aTempKey[j] = static_cast<sal_uInt8>( aKey[j] ^ i ); |
1189 | |
|
1190 | 0 | if (rtl_cipher_initARCFOUR( pData->m_aCipher, rtl_Cipher_DirectionEncode, |
1191 | 0 | aTempKey, sizeof(aTempKey), nullptr, 0 ) |
1192 | 0 | != rtl_Cipher_E_None) |
1193 | 0 | { |
1194 | 0 | return false; //TODO: differentiate "failed to decrypt" from "wrong password" |
1195 | 0 | } |
1196 | 0 | rtl_cipher_encodeARCFOUR( pData->m_aCipher, |
1197 | 0 | nEncryptedEntry.data(), 16, |
1198 | 0 | nEncryptedEntry.data(), 16 ); // encrypt in place |
1199 | 0 | } |
1200 | 0 | bValid = (memcmp( nEncryptedEntry.data(), pData->m_aUEntry, 16 ) == 0); |
1201 | 0 | } |
1202 | 0 | return bValid; |
1203 | 0 | } |
1204 | | |
1205 | | bool PDFFile::usesSupportedEncryptionFormat() const |
1206 | 0 | { |
1207 | 0 | return m_pData->m_bStandardHandler && |
1208 | 0 | m_pData->m_nAlgoVersion >= 1 && |
1209 | 0 | m_pData->m_nAlgoVersion <= 2 && |
1210 | 0 | m_pData->m_nStandardRevision >= 2 && |
1211 | 0 | m_pData->m_nStandardRevision <= 3; |
1212 | 0 | } |
1213 | | |
1214 | | bool PDFFile::setupDecryptionData( const OString& rPwd ) const |
1215 | 0 | { |
1216 | 0 | if( !impl_getData()->m_bIsEncrypted ) |
1217 | 0 | return rPwd.isEmpty(); |
1218 | | |
1219 | | // check if we can handle this encryption at all |
1220 | 0 | if( ! usesSupportedEncryptionFormat() ) |
1221 | 0 | return false; |
1222 | | |
1223 | 0 | if( ! m_pData->m_aCipher ) |
1224 | 0 | m_pData->m_aCipher = rtl_cipher_createARCFOUR(rtl_Cipher_ModeStream); |
1225 | | |
1226 | | // first try user password |
1227 | 0 | bool bValid = check_user_password( rPwd, m_pData.get() ); |
1228 | |
|
1229 | 0 | if( ! bValid ) |
1230 | 0 | { |
1231 | | // try owner password |
1232 | | // see PDF reference 1.4 Algorithm 3.7 |
1233 | 0 | sal_uInt8 aKey[ENCRYPTION_KEY_LEN]; |
1234 | 0 | sal_uInt8 nPwd[ENCRYPTION_BUF_LEN] = {}; |
1235 | 0 | sal_uInt32 nKeyLen = password_to_key( rPwd, aKey, m_pData.get(), true ); |
1236 | 0 | if( m_pData->m_nStandardRevision == 2 ) |
1237 | 0 | { |
1238 | 0 | if (rtl_cipher_initARCFOUR( m_pData->m_aCipher, rtl_Cipher_DirectionDecode, |
1239 | 0 | aKey, nKeyLen, nullptr, 0 ) |
1240 | 0 | != rtl_Cipher_E_None) |
1241 | 0 | { |
1242 | 0 | return false; //TODO: differentiate "failed to decrypt" from "wrong password" |
1243 | 0 | } |
1244 | 0 | rtl_cipher_decodeARCFOUR( m_pData->m_aCipher, |
1245 | 0 | m_pData->m_aOEntry, 32, |
1246 | 0 | nPwd, 32 ); |
1247 | 0 | } |
1248 | 0 | else if( m_pData->m_nStandardRevision == 3 ) |
1249 | 0 | { |
1250 | 0 | memcpy( nPwd, m_pData->m_aOEntry, 32 ); |
1251 | 0 | for( int i = 19; i >= 0; i-- ) |
1252 | 0 | { |
1253 | 0 | sal_uInt8 nTempKey[ENCRYPTION_KEY_LEN]; |
1254 | 0 | for( size_t j = 0; j < sizeof(nTempKey); j++ ) |
1255 | 0 | nTempKey[j] = sal_uInt8(aKey[j] ^ i); |
1256 | 0 | if (rtl_cipher_initARCFOUR( m_pData->m_aCipher, rtl_Cipher_DirectionDecode, |
1257 | 0 | nTempKey, nKeyLen, nullptr, 0 ) |
1258 | 0 | != rtl_Cipher_E_None) |
1259 | 0 | { |
1260 | 0 | return false; //TODO: differentiate "failed to decrypt" from "wrong password" |
1261 | 0 | } |
1262 | 0 | rtl_cipher_decodeARCFOUR( m_pData->m_aCipher, |
1263 | 0 | nPwd, 32, |
1264 | 0 | nPwd, 32 ); // decrypt inplace |
1265 | 0 | } |
1266 | 0 | } |
1267 | 0 | bValid = check_user_password( OString( reinterpret_cast<char*>(nPwd), 32 ), m_pData.get() ); |
1268 | 0 | } |
1269 | | |
1270 | 0 | return bValid; |
1271 | 0 | } |
1272 | | |
1273 | | PDFFileImplData* PDFFile::impl_getData() const |
1274 | 0 | { |
1275 | 0 | if( m_pData ) |
1276 | 0 | return m_pData.get(); |
1277 | 0 | m_pData.reset( new PDFFileImplData ); |
1278 | | // check for encryption dict in a trailer |
1279 | 0 | unsigned int nElements = m_aSubElements.size(); |
1280 | 0 | while( nElements-- > 0 ) |
1281 | 0 | { |
1282 | 0 | PDFTrailer* pTrailer = dynamic_cast<PDFTrailer*>(m_aSubElements[nElements].get()); |
1283 | 0 | if( pTrailer && pTrailer->m_pDict ) |
1284 | 0 | { |
1285 | | // search doc id |
1286 | 0 | PDFDict::Map::iterator doc_id = pTrailer->m_pDict->m_aMap.find( "ID"_ostr ); |
1287 | 0 | if( doc_id != pTrailer->m_pDict->m_aMap.end() ) |
1288 | 0 | { |
1289 | 0 | PDFArray* pArr = dynamic_cast<PDFArray*>(doc_id->second); |
1290 | 0 | if( pArr && !pArr->m_aSubElements.empty() ) |
1291 | 0 | { |
1292 | 0 | PDFString* pStr = dynamic_cast<PDFString*>(pArr->m_aSubElements[0].get()); |
1293 | 0 | if( pStr ) |
1294 | 0 | m_pData->m_aDocID = pStr->getFilteredString(); |
1295 | | #if OSL_DEBUG_LEVEL > 0 |
1296 | | OUStringBuffer aTmp; |
1297 | | for( int i = 0; i < m_pData->m_aDocID.getLength(); i++ ) |
1298 | | aTmp.append(static_cast<sal_Int32>(sal_uInt8(m_pData->m_aDocID[i])), 16); |
1299 | | SAL_INFO("sdext.pdfimport.pdfparse", "DocId is <" << aTmp.makeStringAndClear() << ">"); |
1300 | | #endif |
1301 | 0 | } |
1302 | 0 | } |
1303 | | // search Encrypt entry |
1304 | 0 | PDFDict::Map::iterator enc = |
1305 | 0 | pTrailer->m_pDict->m_aMap.find( "Encrypt"_ostr ); |
1306 | 0 | if( enc != pTrailer->m_pDict->m_aMap.end() ) |
1307 | 0 | { |
1308 | 0 | PDFDict* pDict = dynamic_cast<PDFDict*>(enc->second); |
1309 | 0 | if( ! pDict ) |
1310 | 0 | { |
1311 | 0 | PDFObjectRef* pRef = dynamic_cast<PDFObjectRef*>(enc->second); |
1312 | 0 | if( pRef ) |
1313 | 0 | { |
1314 | 0 | PDFObject* pObj = findObject( pRef ); |
1315 | 0 | if( pObj && pObj->m_pObject ) |
1316 | 0 | pDict = dynamic_cast<PDFDict*>(pObj->m_pObject); |
1317 | 0 | } |
1318 | 0 | } |
1319 | 0 | if( pDict ) |
1320 | 0 | { |
1321 | 0 | PDFDict::Map::iterator filter = pDict->m_aMap.find( "Filter"_ostr ); |
1322 | 0 | PDFDict::Map::iterator version = pDict->m_aMap.find( "V"_ostr ); |
1323 | 0 | PDFDict::Map::iterator len = pDict->m_aMap.find( "Length"_ostr ); |
1324 | 0 | PDFDict::Map::iterator o_ent = pDict->m_aMap.find( "O"_ostr ); |
1325 | 0 | PDFDict::Map::iterator u_ent = pDict->m_aMap.find( "U"_ostr ); |
1326 | 0 | PDFDict::Map::iterator r_ent = pDict->m_aMap.find( "R"_ostr ); |
1327 | 0 | PDFDict::Map::iterator p_ent = pDict->m_aMap.find( "P"_ostr ); |
1328 | 0 | if( filter != pDict->m_aMap.end() ) |
1329 | 0 | { |
1330 | 0 | m_pData->m_bIsEncrypted = true; |
1331 | 0 | m_pData->m_nKeyLength = 5; |
1332 | 0 | if( version != pDict->m_aMap.end() ) |
1333 | 0 | { |
1334 | 0 | PDFNumber* pNum = dynamic_cast<PDFNumber*>(version->second); |
1335 | 0 | if( pNum ) |
1336 | 0 | m_pData->m_nAlgoVersion = static_cast<sal_uInt32>(pNum->m_fValue); |
1337 | 0 | } |
1338 | 0 | if( m_pData->m_nAlgoVersion >= 3 ) |
1339 | 0 | m_pData->m_nKeyLength = 16; |
1340 | 0 | if( len != pDict->m_aMap.end() ) |
1341 | 0 | { |
1342 | 0 | PDFNumber* pNum = dynamic_cast<PDFNumber*>(len->second); |
1343 | 0 | if( pNum ) |
1344 | 0 | { |
1345 | 0 | sal_uInt32 nKeyLength = static_cast<sal_uInt32>(pNum->m_fValue) / 8; |
1346 | 0 | if (nKeyLength > ENCRYPTION_KEY_LEN) |
1347 | 0 | { |
1348 | 0 | SAL_WARN("sdext.pdfimport.pdfparse", "entry has length " << nKeyLength << " which is greater than " << ENCRYPTION_KEY_LEN); |
1349 | 0 | nKeyLength = ENCRYPTION_KEY_LEN; |
1350 | 0 | } |
1351 | 0 | m_pData->m_nKeyLength = nKeyLength; |
1352 | 0 | } |
1353 | 0 | } |
1354 | 0 | PDFName* pFilter = dynamic_cast<PDFName*>(filter->second); |
1355 | 0 | if( pFilter && pFilter->getFilteredName() == "Standard" ) |
1356 | 0 | m_pData->m_bStandardHandler = true; |
1357 | 0 | if( o_ent != pDict->m_aMap.end() ) |
1358 | 0 | { |
1359 | 0 | PDFString* pString = dynamic_cast<PDFString*>(o_ent->second); |
1360 | 0 | if( pString ) |
1361 | 0 | { |
1362 | 0 | OString aEnt = pString->getFilteredString(); |
1363 | 0 | if( aEnt.getLength() == 32 ) |
1364 | 0 | memcpy( m_pData->m_aOEntry, aEnt.getStr(), 32 ); |
1365 | | #if OSL_DEBUG_LEVEL > 0 |
1366 | | else |
1367 | | { |
1368 | | OUStringBuffer aTmp; |
1369 | | for( int i = 0; i < aEnt.getLength(); i++ ) |
1370 | | aTmp.append(" " + OUString::number(sal_uInt8(aEnt[i]), 16)); |
1371 | | SAL_WARN("sdext.pdfimport.pdfparse", |
1372 | | "O entry has length " << static_cast<int>(aEnt.getLength()) << ", should be 32 <" << aTmp.makeStringAndClear() << ">" ); |
1373 | | } |
1374 | | #endif |
1375 | 0 | } |
1376 | 0 | } |
1377 | 0 | if( u_ent != pDict->m_aMap.end() ) |
1378 | 0 | { |
1379 | 0 | PDFString* pString = dynamic_cast<PDFString*>(u_ent->second); |
1380 | 0 | if( pString ) |
1381 | 0 | { |
1382 | 0 | OString aEnt = pString->getFilteredString(); |
1383 | 0 | if( aEnt.getLength() == 32 ) |
1384 | 0 | memcpy( m_pData->m_aUEntry, aEnt.getStr(), 32 ); |
1385 | | #if OSL_DEBUG_LEVEL > 0 |
1386 | | else |
1387 | | { |
1388 | | OUStringBuffer aTmp; |
1389 | | for( int i = 0; i < aEnt.getLength(); i++ ) |
1390 | | aTmp.append(" " + OUString::number(sal_uInt8(aEnt[i]), 16)); |
1391 | | SAL_WARN("sdext.pdfimport.pdfparse", |
1392 | | "U entry has length " << static_cast<int>(aEnt.getLength()) << ", should be 32 <" << aTmp.makeStringAndClear() << ">" ); |
1393 | | } |
1394 | | #endif |
1395 | 0 | } |
1396 | 0 | } |
1397 | 0 | if( r_ent != pDict->m_aMap.end() ) |
1398 | 0 | { |
1399 | 0 | PDFNumber* pNum = dynamic_cast<PDFNumber*>(r_ent->second); |
1400 | 0 | if( pNum ) |
1401 | 0 | m_pData->m_nStandardRevision = static_cast<sal_uInt32>(pNum->m_fValue); |
1402 | 0 | } |
1403 | 0 | if( p_ent != pDict->m_aMap.end() ) |
1404 | 0 | { |
1405 | 0 | PDFNumber* pNum = dynamic_cast<PDFNumber*>(p_ent->second); |
1406 | 0 | if( pNum ) |
1407 | 0 | m_pData->m_nPEntry = static_cast<sal_uInt32>(static_cast<sal_Int32>(pNum->m_fValue)); |
1408 | 0 | SAL_INFO("sdext.pdfimport.pdfparse", "p entry is " << m_pData->m_nPEntry ); |
1409 | 0 | } |
1410 | | |
1411 | 0 | SAL_INFO("sdext.pdfimport.pdfparse", "Encryption dict: sec handler: " << (pFilter ? pFilter->getFilteredName() : u"<unknown>"_ustr) << ", version = " << static_cast<int>(m_pData->m_nAlgoVersion) << ", revision = " << static_cast<int>(m_pData->m_nStandardRevision) << ", key length = " << m_pData->m_nKeyLength ); |
1412 | 0 | break; |
1413 | 0 | } |
1414 | 0 | } |
1415 | 0 | } |
1416 | 0 | } |
1417 | 0 | } |
1418 | | |
1419 | 0 | return m_pData.get(); |
1420 | 0 | } |
1421 | | |
1422 | | bool PDFFile::emit( EmitContext& rWriteContext ) const |
1423 | 0 | { |
1424 | 0 | setEmitData( rWriteContext, new EmitImplData( this ) ); |
1425 | |
|
1426 | 0 | OString aBuf = |
1427 | 0 | "%PDF-" + |
1428 | 0 | OString::number( sal_Int32( m_nMajor ) ) + |
1429 | 0 | "." + |
1430 | 0 | OString::number( sal_Int32( m_nMinor ) ) + |
1431 | 0 | "\n"; |
1432 | 0 | if( ! rWriteContext.write( aBuf.getStr(), aBuf.getLength() ) ) |
1433 | 0 | return false; |
1434 | 0 | return emitSubElements( rWriteContext ); |
1435 | 0 | } |
1436 | | |
1437 | | PDFEntry* PDFFile::clone() const |
1438 | 0 | { |
1439 | 0 | PDFFile* pNewFl = new PDFFile(); |
1440 | 0 | pNewFl->m_nMajor = m_nMajor; |
1441 | 0 | pNewFl->m_nMinor = m_nMinor; |
1442 | 0 | cloneSubElements( pNewFl->m_aSubElements ); |
1443 | 0 | return pNewFl; |
1444 | 0 | } |
1445 | | |
1446 | | PDFPart::~PDFPart() |
1447 | | { |
1448 | | } |
1449 | | |
1450 | | bool PDFPart::emit( EmitContext& rWriteContext ) const |
1451 | 0 | { |
1452 | 0 | return emitSubElements( rWriteContext ); |
1453 | 0 | } |
1454 | | |
1455 | | PDFEntry* PDFPart::clone() const |
1456 | 0 | { |
1457 | 0 | PDFPart* pNewPt = new PDFPart(); |
1458 | 0 | cloneSubElements( pNewPt->m_aSubElements ); |
1459 | 0 | return pNewPt; |
1460 | 0 | } |
1461 | | |
1462 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |