1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <pdfparse.hxx>
23 #include <comphelper/hash.hxx>
25 #include <rtl/strbuf.hxx>
26 #include <rtl/ustring.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <rtl/digest.h>
29 #include <rtl/cipher.h>
30 #include <sal/log.hxx>
45 // xref table: maps object number to a pair of (generation, buffer offset)
46 typedef std::map
< unsigned int, std::pair
< unsigned int, unsigned int > > XRefTable
;
47 XRefTable m_aXRefTable
;
48 // container of all indirect objects (usually a PDFFile*)
49 const PDFContainer
* m_pObjectContainer
;
50 unsigned int m_nDecryptObject
;
51 unsigned int m_nDecryptGeneration
;
53 // returns true if the xref table was updated
54 bool insertXref( unsigned int nObject
, unsigned int nGeneration
, unsigned int nOffset
)
56 XRefTable::iterator it
= m_aXRefTable
.find( nObject
);
57 if( it
== m_aXRefTable
.end() )
60 m_aXRefTable
[ nObject
] = std::pair
<unsigned int, unsigned int>(nGeneration
,nOffset
);
63 // update old entry, if generation number is higher
64 if( it
->second
.first
< nGeneration
)
66 it
->second
= std::pair
<unsigned int, unsigned int>(nGeneration
,nOffset
);
72 explicit EmitImplData( const PDFContainer
* pTopContainer
) :
73 m_pObjectContainer( pTopContainer
),
74 m_nDecryptObject( 0 ),
75 m_nDecryptGeneration( 0 )
77 void decrypt( const sal_uInt8
* pInBuffer
, sal_uInt32 nLen
, sal_uInt8
* pOutBuffer
,
78 unsigned int nObject
, unsigned int nGeneration
) const
80 const PDFFile
* pFile
= dynamic_cast<const PDFFile
*>(m_pObjectContainer
);
81 pFile
&& pFile
->decrypt( pInBuffer
, nLen
, pOutBuffer
, nObject
, nGeneration
);
84 void setDecryptObject( unsigned int nObject
, unsigned int nGeneration
)
86 m_nDecryptObject
= nObject
;
87 m_nDecryptGeneration
= nGeneration
;
93 using namespace pdfparse
;
95 EmitContext::EmitContext( const PDFContainer
* pTop
) :
100 m_pImplData
.reset( new EmitImplData( pTop
) );
103 EmitContext::~EmitContext()
107 PDFEntry::~PDFEntry()
111 EmitImplData
* PDFEntry::getEmitData( EmitContext
const & rContext
)
113 return rContext
.m_pImplData
.get();
116 void PDFEntry::setEmitData( EmitContext
& rContext
, EmitImplData
* pNewEmitData
)
118 if( rContext
.m_pImplData
&& rContext
.m_pImplData
.get() != pNewEmitData
)
119 rContext
.m_pImplData
.reset();
120 rContext
.m_pImplData
.reset( pNewEmitData
);
123 PDFValue::~PDFValue()
127 PDFComment::~PDFComment()
131 bool PDFComment::emit( EmitContext
& rWriteContext
) const
133 return rWriteContext
.write( m_aComment
.getStr(), m_aComment
.getLength() );
136 PDFEntry
* PDFComment::clone() const
138 return new PDFComment( m_aComment
);
145 bool PDFName::emit( EmitContext
& rWriteContext
) const
147 if( ! rWriteContext
.write( " /", 2 ) )
149 return rWriteContext
.write( m_aName
.getStr(), m_aName
.getLength() );
152 PDFEntry
* PDFName::clone() const
154 return new PDFName( m_aName
);
157 OUString
PDFName::getFilteredName() const
159 OStringBuffer
aFilter( m_aName
.getLength() );
160 const char* pStr
= m_aName
.getStr();
161 unsigned int nLen
= m_aName
.getLength();
162 for( unsigned int i
= 0; i
< nLen
; i
++ )
164 if( (i
< nLen
- 3) && pStr
[i
] == '#' )
168 if( pStr
[i
] >= '0' && pStr
[i
] <= '9' )
169 rResult
= char( pStr
[i
]-'0' ) << 4;
170 else if( pStr
[i
] >= 'a' && pStr
[i
] <= 'f' )
171 rResult
= char( pStr
[i
]-'a' + 10 ) << 4;
172 else if( pStr
[i
] >= 'A' && pStr
[i
] <= 'F' )
173 rResult
= char( pStr
[i
]-'A' + 10 ) << 4;
175 if( pStr
[i
] >= '0' && pStr
[i
] <= '9' )
176 rResult
|= char( pStr
[i
]-'0' );
177 else if( pStr
[i
] >= 'a' && pStr
[i
] <= 'f' )
178 rResult
|= char( pStr
[i
]-'a' + 10 );
179 else if( pStr
[i
] >= 'A' && pStr
[i
] <= 'F' )
180 rResult
|= char( pStr
[i
]-'A' + 10 );
181 aFilter
.append( rResult
);
184 aFilter
.append( pStr
[i
] );
186 return OStringToOUString( aFilter
, RTL_TEXTENCODING_UTF8
);
189 PDFString::~PDFString()
193 bool PDFString::emit( EmitContext
& rWriteContext
) const
195 if( ! rWriteContext
.write( " ", 1 ) )
197 EmitImplData
* pEData
= getEmitData( rWriteContext
);
198 if( rWriteContext
.m_bDecrypt
&& pEData
&& pEData
->m_nDecryptObject
)
200 OString
aFiltered( getFilteredString() );
201 // decrypt inplace (evil since OString is supposed to be const
202 // however in this case we know that getFilteredString returned a singular string instance
203 pEData
->decrypt( reinterpret_cast<sal_uInt8
const *>(aFiltered
.getStr()), aFiltered
.getLength(),
204 reinterpret_cast<sal_uInt8
*>(const_cast<char *>(aFiltered
.getStr())),
205 pEData
->m_nDecryptObject
, pEData
->m_nDecryptGeneration
);
206 // check for string or hex string
207 const char* pStr
= aFiltered
.getStr();
208 if( aFiltered
.getLength() > 1 &&
209 ( (static_cast<unsigned char>(pStr
[0]) == 0xff && static_cast<unsigned char>(pStr
[1]) == 0xfe) ||
210 (static_cast<unsigned char>(pStr
[0]) == 0xfe && static_cast<unsigned char>(pStr
[1]) == 0xff) ) )
212 static const char pHexTab
[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
213 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
214 if( ! rWriteContext
.write( "<", 1 ) )
216 for( sal_Int32 i
= 0; i
< aFiltered
.getLength(); i
++ )
218 if( ! rWriteContext
.write( pHexTab
+ ((sal_uInt32(pStr
[i
]) >> 4) & 0x0f), 1 ) )
220 if( ! rWriteContext
.write( pHexTab
+ (sal_uInt32(pStr
[i
]) & 0x0f), 1 ) )
223 if( ! rWriteContext
.write( ">", 1 ) )
228 if( ! rWriteContext
.write( "(", 1 ) )
230 if( ! rWriteContext
.write( aFiltered
.getStr(), aFiltered
.getLength() ) )
232 if( ! rWriteContext
.write( ")", 1 ) )
237 return rWriteContext
.write( m_aString
.getStr(), m_aString
.getLength() );
240 PDFEntry
* PDFString::clone() const
242 return new PDFString( m_aString
);
245 OString
PDFString::getFilteredString() const
247 int nLen
= m_aString
.getLength();
248 OStringBuffer
aBuf( nLen
);
250 const char* pStr
= m_aString
.getStr();
253 const char* pRun
= pStr
+1;
254 while( pRun
- pStr
< nLen
-1 )
259 if( pRun
- pStr
< nLen
)
264 else if( *pRun
== 'r' )
266 else if( *pRun
== 't' )
268 else if( *pRun
== 'b' )
270 else if( *pRun
== 'f' )
272 else if( *pRun
== '(' )
274 else if( *pRun
== ')' )
276 else if( *pRun
== '\\' )
278 else if( *pRun
== '\n' )
283 else if( *pRun
== '\r' )
293 while( i
++ < 3 && *pRun
>= '0' && *pRun
<= '7' )
294 aEsc
= 8*aEsc
+ (*pRun
++ - '0');
295 // move pointer back to last character of octal sequence
302 aBuf
.append( *pRun
);
303 // move pointer to next character
307 else if( *pStr
== '<' )
309 const char* pRun
= pStr
+1;
310 while( *pRun
!= '>' && pRun
- pStr
< nLen
)
313 if( *pRun
>= '0' && *pRun
<= '9' )
314 rResult
= char( ( *pRun
-'0' ) << 4 );
315 else if( *pRun
>= 'a' && *pRun
<= 'f' )
316 rResult
= char( ( *pRun
-'a' + 10 ) << 4 );
317 else if( *pRun
>= 'A' && *pRun
<= 'F' )
318 rResult
= char( ( *pRun
-'A' + 10 ) << 4 );
320 if( *pRun
!= '>' && pRun
- pStr
< nLen
)
322 if( *pRun
>= '0' && *pRun
<= '9' )
323 rResult
|= char( *pRun
-'0' );
324 else if( *pRun
>= 'a' && *pRun
<= 'f' )
325 rResult
|= char( *pRun
-'a' + 10 );
326 else if( *pRun
>= 'A' && *pRun
<= 'F' )
327 rResult
|= char( *pRun
-'A' + 10 );
330 aBuf
.append( rResult
);
334 return aBuf
.makeStringAndClear();
337 PDFNumber::~PDFNumber()
341 bool PDFNumber::emit( EmitContext
& rWriteContext
) const
343 OStringBuffer
aBuf( 32 );
346 double fValue
= m_fValue
;
355 sal_Int64 nInt
= static_cast<sal_Int64
>(fValue
);
356 fValue
-= static_cast<double>(nInt
);
357 // optimizing hardware may lead to a value of 1.0 after the subtraction
358 if( fValue
== 1.0 || log10( 1.0-fValue
) <= -nPrecision
)
366 fValue
*= pow( 10.0, static_cast<double>(nPrecision
) );
367 nFrac
= static_cast<sal_Int64
>(fValue
);
369 if( bNeg
&& ( nInt
|| nFrac
) )
376 sal_Int64 nBound
= static_cast<sal_Int64
>(pow( 10.0, nPrecision
- 1.0 )+0.5);
377 for ( i
= 0; ( i
< nPrecision
) && nFrac
; i
++ )
379 sal_Int64 nNumb
= nFrac
/ nBound
;
380 nFrac
-= nNumb
* nBound
;
381 aBuf
.append( nNumb
);
386 return rWriteContext
.write( aBuf
.getStr(), aBuf
.getLength() );
389 PDFEntry
* PDFNumber::clone() const
391 return new PDFNumber( m_fValue
);
399 bool PDFBool::emit( EmitContext
& rWriteContext
) const
401 return m_bValue
? rWriteContext
.write( " true", 5 ) : rWriteContext
.write( " false", 6 );
404 PDFEntry
* PDFBool::clone() const
406 return new PDFBool( m_bValue
);
413 bool PDFNull::emit( EmitContext
& rWriteContext
) const
415 return rWriteContext
.write( " null", 5 );
418 PDFEntry
* PDFNull::clone() const
420 return new PDFNull();
424 PDFObjectRef::~PDFObjectRef()
428 bool PDFObjectRef::emit( EmitContext
& rWriteContext
) const
432 OString::number( sal_Int32( m_nNumber
) ) +
434 OString::number( sal_Int32( m_nGeneration
) ) +
436 return rWriteContext
.write( aBuf
.getStr(), aBuf
.getLength() );
439 PDFEntry
* PDFObjectRef::clone() const
441 return new PDFObjectRef( m_nNumber
, m_nGeneration
);
444 PDFContainer::~PDFContainer()
448 bool PDFContainer::emitSubElements( EmitContext
& rWriteContext
) const
450 int nEle
= m_aSubElements
.size();
451 for( int i
= 0; i
< nEle
; i
++ )
453 if( rWriteContext
.m_bDecrypt
)
455 const PDFName
* pName
= dynamic_cast<PDFName
*>(m_aSubElements
[i
].get());
456 if (pName
&& pName
->m_aName
== "Encrypt")
462 if( ! m_aSubElements
[i
]->emit( rWriteContext
) )
468 void PDFContainer::cloneSubElements( std::vector
<std::unique_ptr
<PDFEntry
>>& rNewSubElements
) const
470 int nEle
= m_aSubElements
.size();
471 for( int i
= 0; i
< nEle
; i
++ )
472 rNewSubElements
.emplace_back( m_aSubElements
[i
]->clone() );
475 PDFObject
* PDFContainer::findObject( unsigned int nNumber
, unsigned int nGeneration
) const
477 unsigned int nEle
= m_aSubElements
.size();
478 for( unsigned int i
= 0; i
< nEle
; i
++ )
480 PDFObject
* pObject
= dynamic_cast<PDFObject
*>(m_aSubElements
[i
].get());
482 pObject
->m_nNumber
== nNumber
&&
483 pObject
->m_nGeneration
== nGeneration
)
491 PDFArray::~PDFArray()
495 bool PDFArray::emit( EmitContext
& rWriteContext
) const
497 if( ! rWriteContext
.write( "[", 1 ) )
499 if( ! emitSubElements( rWriteContext
) )
501 return rWriteContext
.write( "]", 1 );
504 PDFEntry
* PDFArray::clone() const
506 PDFArray
* pNewAr
= new PDFArray();
507 cloneSubElements( pNewAr
->m_aSubElements
);
515 bool PDFDict::emit( EmitContext
& rWriteContext
) const
517 if( ! rWriteContext
.write( "<<\n", 3 ) )
519 if( ! emitSubElements( rWriteContext
) )
521 return rWriteContext
.write( "\n>>\n", 4 );
524 void PDFDict::insertValue( const OString
& rName
, std::unique_ptr
<PDFEntry
> pValue
)
529 PDFEntry
* pValueTmp
= nullptr;
530 std::unordered_map
<OString
,PDFEntry
*>::iterator it
= m_aMap
.find( rName
);
531 if( it
== m_aMap
.end() )
533 // new name/value, pair, append it
534 m_aSubElements
.emplace_back(std::make_unique
<PDFName
>(rName
));
535 m_aSubElements
.emplace_back( std::move(pValue
) );
536 pValueTmp
= m_aSubElements
.back().get();
540 unsigned int nSub
= m_aSubElements
.size();
541 for( unsigned int i
= 0; i
< nSub
; i
++ )
542 if( m_aSubElements
[i
].get() == it
->second
)
544 m_aSubElements
[i
] = std::move(pValue
);
545 pValueTmp
= m_aSubElements
[i
].get();
550 m_aMap
[ rName
] = pValueTmp
;
553 void PDFDict::eraseValue( std::string_view rName
)
555 unsigned int nEle
= m_aSubElements
.size();
556 for( unsigned int i
= 0; i
< nEle
; i
++ )
558 PDFName
* pName
= dynamic_cast<PDFName
*>(m_aSubElements
[i
].get());
559 if( pName
&& pName
->m_aName
== rName
)
561 for( unsigned int j
= i
+1; j
< nEle
; j
++ )
563 if( dynamic_cast<PDFComment
*>(m_aSubElements
[j
].get()) == nullptr )
565 // remove and free subelements from vector
566 m_aSubElements
.erase( m_aSubElements
.begin()+j
);
567 m_aSubElements
.erase( m_aSubElements
.begin()+i
);
576 PDFEntry
* PDFDict::buildMap()
581 unsigned int nEle
= m_aSubElements
.size();
582 PDFName
* pName
= nullptr;
583 for( unsigned int i
= 0; i
< nEle
; i
++ )
585 if( dynamic_cast<PDFComment
*>(m_aSubElements
[i
].get()) == nullptr )
589 m_aMap
[ pName
->m_aName
] = m_aSubElements
[i
].get();
592 else if( (pName
= dynamic_cast<PDFName
*>(m_aSubElements
[i
].get())) == nullptr )
593 return m_aSubElements
[i
].get();
599 PDFEntry
* PDFDict::clone() const
601 PDFDict
* pNewDict
= new PDFDict();
602 cloneSubElements( pNewDict
->m_aSubElements
);
603 pNewDict
->buildMap();
607 PDFStream::~PDFStream()
611 bool PDFStream::emit( EmitContext
& rWriteContext
) const
613 return rWriteContext
.copyOrigBytes( m_nBeginOffset
, m_nEndOffset
-m_nBeginOffset
);
616 PDFEntry
* PDFStream::clone() const
618 return new PDFStream( m_nBeginOffset
, m_nEndOffset
, nullptr );
621 unsigned int PDFStream::getDictLength( const PDFContainer
* pContainer
) const
625 // find /Length entry, can either be a direct or indirect number object
626 std::unordered_map
<OString
,PDFEntry
*>::const_iterator it
=
627 m_pDict
->m_aMap
.find( "Length"_ostr
);
628 if( it
== m_pDict
->m_aMap
.end() )
630 PDFNumber
* pNum
= dynamic_cast<PDFNumber
*>(it
->second
);
631 if( ! pNum
&& pContainer
)
633 PDFObjectRef
* pRef
= dynamic_cast<PDFObjectRef
*>(it
->second
);
636 int nEle
= pContainer
->m_aSubElements
.size();
637 for (int i
= 0; i
< nEle
; i
++)
639 PDFObject
* pObj
= dynamic_cast<PDFObject
*>(pContainer
->m_aSubElements
[i
].get());
641 pObj
->m_nNumber
== pRef
->m_nNumber
&&
642 pObj
->m_nGeneration
== pRef
->m_nGeneration
)
644 if( pObj
->m_pObject
)
645 pNum
= dynamic_cast<PDFNumber
*>(pObj
->m_pObject
);
651 return pNum
? static_cast<unsigned int>(pNum
->m_fValue
) : 0;
654 PDFObject::~PDFObject()
658 bool PDFObject::getDeflatedStream( std::unique_ptr
<char[]>& rpStream
, unsigned int* pBytes
, const PDFContainer
* pObjectContainer
, EmitContext
& rContext
) const
660 bool bIsDeflated
= false;
661 if( m_pStream
&& m_pStream
->m_pDict
&&
662 m_pStream
->m_nEndOffset
> m_pStream
->m_nBeginOffset
+15
665 unsigned int nOuterStreamLen
= m_pStream
->m_nEndOffset
- m_pStream
->m_nBeginOffset
;
666 rpStream
.reset(new char[ nOuterStreamLen
]);
667 unsigned int nRead
= rContext
.readOrigBytes( m_pStream
->m_nBeginOffset
, nOuterStreamLen
, rpStream
.get() );
668 if( nRead
!= nOuterStreamLen
)
674 // is there a filter entry ?
675 std::unordered_map
<OString
,PDFEntry
*>::const_iterator it
=
676 m_pStream
->m_pDict
->m_aMap
.find( "Filter"_ostr
);
677 if( it
!= m_pStream
->m_pDict
->m_aMap
.end() )
679 PDFName
* pFilter
= dynamic_cast<PDFName
*>(it
->second
);
682 PDFArray
* pArray
= dynamic_cast<PDFArray
*>(it
->second
);
683 if( pArray
&& ! pArray
->m_aSubElements
.empty() )
685 pFilter
= dynamic_cast<PDFName
*>(pArray
->m_aSubElements
.front().get());
689 // is the (first) filter FlateDecode ?
690 if (pFilter
&& pFilter
->m_aName
== "FlateDecode")
695 // prepare compressed data section
696 char* pStream
= rpStream
.get();
697 if( pStream
[0] == 's' )
698 pStream
+= 6; // skip "stream"
699 // skip line end after "stream"
700 while( *pStream
== '\r' || *pStream
== '\n' )
702 // get the compressed length
703 *pBytes
= m_pStream
->getDictLength( pObjectContainer
);
704 if( pStream
!= rpStream
.get() )
705 memmove( rpStream
.get(), pStream
, *pBytes
);
706 if( rContext
.m_bDecrypt
)
708 EmitImplData
* pEData
= getEmitData( rContext
);
709 pEData
->decrypt( reinterpret_cast<const sal_uInt8
*>(rpStream
.get()),
711 reinterpret_cast<sal_uInt8
*>(rpStream
.get()),
714 ); // decrypt inplace
724 static void unzipToBuffer( char* pBegin
, unsigned int nLen
,
725 sal_uInt8
** pOutBuf
, sal_uInt32
* pOutLen
)
728 aZStr
.next_in
= reinterpret_cast<Bytef
*>(pBegin
);
729 aZStr
.avail_in
= nLen
;
730 aZStr
.total_out
= aZStr
.total_in
= 0;
731 aZStr
.zalloc
= nullptr;
732 aZStr
.zfree
= nullptr;
733 aZStr
.opaque
= nullptr;
735 int err
= inflateInit(&aZStr
);
737 const unsigned int buf_increment_size
= 16384;
739 if (auto p
= static_cast<sal_uInt8
*>(std::realloc(*pOutBuf
, buf_increment_size
)))
742 aZStr
.next_out
= reinterpret_cast<Bytef
*>(*pOutBuf
);
743 aZStr
.avail_out
= buf_increment_size
;
744 *pOutLen
= buf_increment_size
;
748 while( err
!= Z_STREAM_END
&& err
>= Z_OK
&& aZStr
.avail_in
)
750 err
= inflate( &aZStr
, Z_NO_FLUSH
);
751 if( aZStr
.avail_out
== 0 )
753 if( err
!= Z_STREAM_END
)
755 const int nNewAlloc
= *pOutLen
+ buf_increment_size
;
756 if (auto p
= static_cast<sal_uInt8
*>(std::realloc(*pOutBuf
, nNewAlloc
)))
759 aZStr
.next_out
= reinterpret_cast<Bytef
*>(*pOutBuf
+ *pOutLen
);
760 aZStr
.avail_out
= buf_increment_size
;
761 *pOutLen
= nNewAlloc
;
768 if( err
== Z_STREAM_END
)
770 if( aZStr
.avail_out
> 0 )
771 *pOutLen
-= aZStr
.avail_out
;
776 std::free( *pOutBuf
);
782 void PDFObject::writeStream( EmitContext
& rWriteContext
, const PDFFile
* pParsedFile
) const
787 std::unique_ptr
<char[]> pStream
;
788 unsigned int nBytes
= 0;
789 if( getDeflatedStream( pStream
, &nBytes
, pParsedFile
, rWriteContext
) && nBytes
&& rWriteContext
.m_bDeflate
)
791 sal_uInt8
* pOutBytes
= nullptr;
792 sal_uInt32 nOutBytes
= 0;
793 unzipToBuffer( pStream
.get(), nBytes
, &pOutBytes
, &nOutBytes
);
794 rWriteContext
.write( pOutBytes
, nOutBytes
);
795 std::free( pOutBytes
);
797 else if( pStream
&& nBytes
)
798 rWriteContext
.write( pStream
.get(), nBytes
);
801 bool PDFObject::emit( EmitContext
& rWriteContext
) const
803 if( ! rWriteContext
.write( "\n", 1 ) )
806 EmitImplData
* pEData
= getEmitData( rWriteContext
);
808 pEData
->insertXref( m_nNumber
, m_nGeneration
, rWriteContext
.getCurPos() );
811 OString::number( sal_Int32( m_nNumber
) ) +
813 OString::number( sal_Int32( m_nGeneration
) ) +
815 if( ! rWriteContext
.write( aBuf
.getStr(), aBuf
.getLength() ) )
819 pEData
->setDecryptObject( m_nNumber
, m_nGeneration
);
820 if( (rWriteContext
.m_bDeflate
|| rWriteContext
.m_bDecrypt
) && pEData
)
822 std::unique_ptr
<char[]> pStream
;
823 unsigned int nBytes
= 0;
824 bool bDeflate
= getDeflatedStream( pStream
, &nBytes
, pEData
->m_pObjectContainer
, rWriteContext
);
825 if( pStream
&& nBytes
)
828 sal_uInt8
* pOutBytes
= nullptr;
829 sal_uInt32 nOutBytes
= 0;
830 if( bDeflate
&& rWriteContext
.m_bDeflate
)
831 unzipToBuffer( pStream
.get(), nBytes
, &pOutBytes
, &nOutBytes
);
834 // nothing to deflate, but decryption has happened
835 pOutBytes
= reinterpret_cast<sal_uInt8
*>(pStream
.get());
836 nOutBytes
= static_cast<sal_uInt32
>(nBytes
);
842 std::unique_ptr
<PDFObject
> pClone(static_cast<PDFObject
*>(clone()));
843 // set length in the dictionary to new stream length
844 std::unique_ptr
<PDFNumber
> pNewLen(new PDFNumber( double(nOutBytes
) ));
845 pClone
->m_pStream
->m_pDict
->insertValue( "Length"_ostr
, std::move(pNewLen
) );
847 if( bDeflate
&& rWriteContext
.m_bDeflate
)
849 // delete flatedecode filter
850 std::unordered_map
<OString
,PDFEntry
*>::const_iterator it
=
851 pClone
->m_pStream
->m_pDict
->m_aMap
.find( "Filter"_ostr
);
852 if( it
!= pClone
->m_pStream
->m_pDict
->m_aMap
.end() )
854 PDFName
* pFilter
= dynamic_cast<PDFName
*>(it
->second
);
855 if (pFilter
&& pFilter
->m_aName
== "FlateDecode")
856 pClone
->m_pStream
->m_pDict
->eraseValue( "Filter" );
859 PDFArray
* pArray
= dynamic_cast<PDFArray
*>(it
->second
);
860 if( pArray
&& ! pArray
->m_aSubElements
.empty() )
862 pFilter
= dynamic_cast<PDFName
*>(pArray
->m_aSubElements
.front().get());
863 if (pFilter
&& pFilter
->m_aName
== "FlateDecode")
865 pArray
->m_aSubElements
.erase( pArray
->m_aSubElements
.begin() );
872 // write sub elements except stream
874 unsigned int nEle
= pClone
->m_aSubElements
.size();
875 for( unsigned int i
= 0; i
< nEle
&& bRet
; i
++ )
877 if( pClone
->m_aSubElements
[i
].get() != pClone
->m_pStream
)
878 bRet
= pClone
->m_aSubElements
[i
]->emit( rWriteContext
);
883 bRet
= rWriteContext
.write("stream\n", 7)
884 && rWriteContext
.write(pOutBytes
, nOutBytes
)
885 && rWriteContext
.write("\nendstream\nendobj\n", 18);
886 if( pOutBytes
!= reinterpret_cast<sal_uInt8
*>(pStream
.get()) )
887 std::free( pOutBytes
);
888 pEData
->setDecryptObject( 0, 0 );
891 if( pOutBytes
!= reinterpret_cast<sal_uInt8
*>(pStream
.get()) )
892 std::free( pOutBytes
);
896 bool bRet
= emitSubElements( rWriteContext
) &&
897 rWriteContext
.write( "\nendobj\n", 8 );
899 pEData
->setDecryptObject( 0, 0 );
903 PDFEntry
* PDFObject::clone() const
905 PDFObject
* pNewOb
= new PDFObject( m_nNumber
, m_nGeneration
);
906 cloneSubElements( pNewOb
->m_aSubElements
);
907 unsigned int nEle
= m_aSubElements
.size();
908 for( unsigned int i
= 0; i
< nEle
; i
++ )
910 if( m_aSubElements
[i
].get() == m_pObject
)
911 pNewOb
->m_pObject
= pNewOb
->m_aSubElements
[i
].get();
912 else if( m_aSubElements
[i
].get() == m_pStream
&& pNewOb
->m_pObject
)
914 pNewOb
->m_pStream
= dynamic_cast<PDFStream
*>(pNewOb
->m_aSubElements
[i
].get());
915 PDFDict
* pNewDict
= dynamic_cast<PDFDict
*>(pNewOb
->m_pObject
);
916 if (pNewDict
&& pNewOb
->m_pStream
)
917 pNewOb
->m_pStream
->m_pDict
= pNewDict
;
923 PDFTrailer::~PDFTrailer()
927 bool PDFTrailer::emit( EmitContext
& rWriteContext
) const
930 unsigned int nXRefPos
= rWriteContext
.getCurPos();
931 // begin xref section, object 0 is always free
932 if( ! rWriteContext
.write( "xref\r\n"
934 "0000000000 65535 f\r\n", 31 ) )
936 // check if we are emitting a complete PDF file
937 EmitImplData
* pEData
= getEmitData( rWriteContext
);
941 const EmitImplData::XRefTable
& rXRefs
= pEData
->m_aXRefTable
;
942 EmitImplData::XRefTable::const_iterator section_begin
, section_end
;
943 section_begin
= rXRefs
.begin();
944 while( section_begin
!= rXRefs
.end() )
946 // find end of continuous object numbers
947 section_end
= section_begin
;
948 unsigned int nLast
= section_begin
->first
;
949 while( (++section_end
) != rXRefs
.end() &&
950 section_end
->first
== nLast
+1 )
951 nLast
= section_end
->first
;
952 // write first object number and number of following entries
954 OString::number(sal_Int32( section_begin
->first
) )
956 + OString::number(sal_Int32(nLast
- section_begin
->first
+ 1))
958 if( ! rWriteContext
.write( aBuf
.getStr(), aBuf
.getLength() ) )
960 while( section_begin
!= section_end
)
962 // write 20 char entry of form
963 // 0000offset 00gen n\r\n
965 OString
aOffset( OString::number( section_begin
->second
.second
) );
966 int nPad
= 10 - aOffset
.getLength();
967 for( int i
= 0; i
< nPad
; i
++ )
969 aBuf
.append( aOffset
+ " " );
970 OString
aGeneration( OString::number( section_begin
->second
.first
) );
971 nPad
= 5 - aGeneration
.getLength();
972 for( int i
= 0; i
< nPad
; i
++ )
974 aBuf
.append( aGeneration
+ " n\r\n" );
975 if( ! rWriteContext
.write( aBuf
.getStr(), 20 ) )
981 if( ! rWriteContext
.write( "trailer\n", 8 ) )
983 if( ! emitSubElements( rWriteContext
) )
985 if( ! rWriteContext
.write( "startxref\n", 10 ) )
987 OString
aOffset( OString::number( nXRefPos
) );
988 if( ! rWriteContext
.write( aOffset
.getStr(), aOffset
.getLength() ) )
990 return rWriteContext
.write( "\n%%EOF\n", 7 );
993 PDFEntry
* PDFTrailer::clone() const
995 PDFTrailer
* pNewTr
= new PDFTrailer();
996 cloneSubElements( pNewTr
->m_aSubElements
);
997 unsigned int nEle
= m_aSubElements
.size();
998 for( unsigned int i
= 0; i
< nEle
; i
++ )
1000 if( m_aSubElements
[i
].get() == m_pDict
)
1002 pNewTr
->m_pDict
= dynamic_cast<PDFDict
*>(pNewTr
->m_aSubElements
[i
].get());
1009 #define ENCRYPTION_KEY_LEN 16
1010 #define ENCRYPTION_BUF_LEN 32
1012 namespace pdfparse
{
1013 struct PDFFileImplData
1015 bool m_bIsEncrypted
;
1016 bool m_bStandardHandler
;
1017 sal_uInt32 m_nAlgoVersion
;
1018 sal_uInt32 m_nStandardRevision
;
1019 sal_uInt32 m_nKeyLength
;
1020 sal_uInt8 m_aOEntry
[32] = {};
1021 sal_uInt8 m_aUEntry
[32] = {};
1022 sal_uInt32 m_nPEntry
;
1024 rtlCipher m_aCipher
;
1026 sal_uInt8 m_aDecryptionKey
[ENCRYPTION_KEY_LEN
+5] = {}; // maximum handled key length
1029 m_bIsEncrypted( false ),
1030 m_bStandardHandler( false ),
1031 m_nAlgoVersion( 0 ),
1032 m_nStandardRevision( 0 ),
1035 m_aCipher( nullptr )
1042 rtl_cipher_destroyARCFOUR( m_aCipher
);
1048 : m_nMajor( 0 ), m_nMinor( 0 )
1056 bool PDFFile::isEncrypted() const
1058 return impl_getData()->m_bIsEncrypted
;
1061 bool PDFFile::decrypt( const sal_uInt8
* pInBuffer
, sal_uInt32 nLen
, sal_uInt8
* pOutBuffer
,
1062 unsigned int nObject
, unsigned int nGeneration
) const
1064 if( ! isEncrypted() )
1067 if( ! m_pData
->m_aCipher
)
1068 m_pData
->m_aCipher
= rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream
);
1070 // modify encryption key
1071 sal_uInt32 i
= m_pData
->m_nKeyLength
;
1072 m_pData
->m_aDecryptionKey
[i
++] = sal_uInt8(nObject
&0xff);
1073 m_pData
->m_aDecryptionKey
[i
++] = sal_uInt8((nObject
>>8)&0xff);
1074 m_pData
->m_aDecryptionKey
[i
++] = sal_uInt8((nObject
>>16)&0xff);
1075 m_pData
->m_aDecryptionKey
[i
++] = sal_uInt8(nGeneration
&0xff);
1076 m_pData
->m_aDecryptionKey
[i
++] = sal_uInt8((nGeneration
>>8)&0xff);
1078 ::std::vector
<unsigned char> const aSum(::comphelper::Hash::calculateHash(
1079 m_pData
->m_aDecryptionKey
, i
, ::comphelper::HashType::MD5
));
1084 rtlCipherError aErr
= rtl_cipher_initARCFOUR( m_pData
->m_aCipher
,
1085 rtl_Cipher_DirectionDecode
,
1088 if( aErr
== rtl_Cipher_E_None
)
1089 aErr
= rtl_cipher_decodeARCFOUR( m_pData
->m_aCipher
,
1092 return aErr
== rtl_Cipher_E_None
;
1095 const sal_uInt8 nPadString
[32] =
1097 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
1098 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A
1101 static void pad_or_truncate_to_32( const OString
& rStr
, char* pBuffer
)
1103 int nLen
= rStr
.getLength();
1106 const char* pStr
= rStr
.getStr();
1107 memcpy( pBuffer
, pStr
, nLen
);
1110 pBuffer
[nLen
++] = nPadString
[i
++];
1113 // pass at least pData->m_nKeyLength bytes in
1114 static sal_uInt32
password_to_key( const OString
& rPwd
, sal_uInt8
* pOutKey
, PDFFileImplData
const * pData
, bool bComputeO
)
1116 // see PDF reference 1.4 Algorithm 3.2
1117 // encrypt pad string
1118 char aPadPwd
[ENCRYPTION_BUF_LEN
];
1119 pad_or_truncate_to_32( rPwd
, aPadPwd
);
1120 ::comphelper::Hash
aDigest(::comphelper::HashType::MD5
);
1121 aDigest
.update(reinterpret_cast<unsigned char const*>(aPadPwd
), sizeof(aPadPwd
));
1124 aDigest
.update(pData
->m_aOEntry
, 32);
1125 sal_uInt8 aPEntry
[4];
1126 aPEntry
[0] = static_cast<sal_uInt8
>(pData
->m_nPEntry
& 0xff);
1127 aPEntry
[1] = static_cast<sal_uInt8
>((pData
->m_nPEntry
>> 8 ) & 0xff);
1128 aPEntry
[2] = static_cast<sal_uInt8
>((pData
->m_nPEntry
>> 16) & 0xff);
1129 aPEntry
[3] = static_cast<sal_uInt8
>((pData
->m_nPEntry
>> 24) & 0xff);
1130 aDigest
.update(aPEntry
, sizeof(aPEntry
));
1131 aDigest
.update(reinterpret_cast<unsigned char const*>(pData
->m_aDocID
.getStr()), pData
->m_aDocID
.getLength());
1133 ::std::vector
<unsigned char> nSum(aDigest
.finalize());
1134 if( pData
->m_nStandardRevision
== 3 )
1136 for( int i
= 0; i
< 50; i
++ )
1138 nSum
= ::comphelper::Hash::calculateHash(nSum
.data(), nSum
.size(),
1139 ::comphelper::HashType::MD5
);
1142 sal_uInt32 nLen
= pData
->m_nKeyLength
;
1143 if( nLen
> RTL_DIGEST_LENGTH_MD5
)
1144 nLen
= RTL_DIGEST_LENGTH_MD5
;
1145 memcpy( pOutKey
, nSum
.data(), nLen
);
1149 static bool check_user_password( const OString
& rPwd
, PDFFileImplData
* pData
)
1151 // see PDF reference 1.4 Algorithm 3.6
1152 bool bValid
= false;
1153 sal_uInt8 aKey
[ENCRYPTION_KEY_LEN
];
1154 sal_uInt32 nKeyLen
= password_to_key( rPwd
, aKey
, pData
, false );
1155 // save (at this time potential) decryption key for later use
1156 memcpy( pData
->m_aDecryptionKey
, aKey
, nKeyLen
);
1157 if( pData
->m_nStandardRevision
== 2 )
1159 sal_uInt8 nEncryptedEntry
[ENCRYPTION_BUF_LEN
] = {};
1160 // see PDF reference 1.4 Algorithm 3.4
1161 // encrypt pad string
1162 if (rtl_cipher_initARCFOUR( pData
->m_aCipher
, rtl_Cipher_DirectionEncode
,
1165 != rtl_Cipher_E_None
)
1167 return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1169 rtl_cipher_encodeARCFOUR( pData
->m_aCipher
, nPadString
, sizeof( nPadString
),
1170 nEncryptedEntry
, sizeof( nEncryptedEntry
) );
1171 bValid
= (memcmp( nEncryptedEntry
, pData
->m_aUEntry
, 32 ) == 0);
1173 else if( pData
->m_nStandardRevision
== 3 )
1175 // see PDF reference 1.4 Algorithm 3.5
1176 ::comphelper::Hash
aDigest(::comphelper::HashType::MD5
);
1177 aDigest
.update(nPadString
, sizeof(nPadString
));
1178 aDigest
.update(reinterpret_cast<unsigned char const*>(pData
->m_aDocID
.getStr()), pData
->m_aDocID
.getLength());
1179 ::std::vector
<unsigned char> nEncryptedEntry(aDigest
.finalize());
1180 if (rtl_cipher_initARCFOUR( pData
->m_aCipher
, rtl_Cipher_DirectionEncode
,
1181 aKey
, sizeof(aKey
), nullptr, 0 )
1182 != rtl_Cipher_E_None
)
1184 return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1186 rtl_cipher_encodeARCFOUR( pData
->m_aCipher
,
1187 nEncryptedEntry
.data(), 16,
1188 nEncryptedEntry
.data(), 16 ); // encrypt in place
1189 for( int i
= 1; i
<= 19; i
++ ) // do it 19 times, start with 1
1191 sal_uInt8 aTempKey
[ENCRYPTION_KEY_LEN
];
1192 for( size_t j
= 0; j
< sizeof(aTempKey
); j
++ )
1193 aTempKey
[j
] = static_cast<sal_uInt8
>( aKey
[j
] ^ i
);
1195 if (rtl_cipher_initARCFOUR( pData
->m_aCipher
, rtl_Cipher_DirectionEncode
,
1196 aTempKey
, sizeof(aTempKey
), nullptr, 0 )
1197 != rtl_Cipher_E_None
)
1199 return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1201 rtl_cipher_encodeARCFOUR( pData
->m_aCipher
,
1202 nEncryptedEntry
.data(), 16,
1203 nEncryptedEntry
.data(), 16 ); // encrypt in place
1205 bValid
= (memcmp( nEncryptedEntry
.data(), pData
->m_aUEntry
, 16 ) == 0);
1210 bool PDFFile::usesSupportedEncryptionFormat() const
1212 return m_pData
->m_bStandardHandler
&&
1213 m_pData
->m_nAlgoVersion
>= 1 &&
1214 m_pData
->m_nAlgoVersion
<= 2 &&
1215 m_pData
->m_nStandardRevision
>= 2 &&
1216 m_pData
->m_nStandardRevision
<= 3;
1219 bool PDFFile::setupDecryptionData( const OString
& rPwd
) const
1221 if( !impl_getData()->m_bIsEncrypted
)
1222 return rPwd
.isEmpty();
1224 // check if we can handle this encryption at all
1225 if( ! usesSupportedEncryptionFormat() )
1228 if( ! m_pData
->m_aCipher
)
1229 m_pData
->m_aCipher
= rtl_cipher_createARCFOUR(rtl_Cipher_ModeStream
);
1231 // first try user password
1232 bool bValid
= check_user_password( rPwd
, m_pData
.get() );
1236 // try owner password
1237 // see PDF reference 1.4 Algorithm 3.7
1238 sal_uInt8 aKey
[ENCRYPTION_KEY_LEN
];
1239 sal_uInt8 nPwd
[ENCRYPTION_BUF_LEN
] = {};
1240 sal_uInt32 nKeyLen
= password_to_key( rPwd
, aKey
, m_pData
.get(), true );
1241 if( m_pData
->m_nStandardRevision
== 2 )
1243 if (rtl_cipher_initARCFOUR( m_pData
->m_aCipher
, rtl_Cipher_DirectionDecode
,
1244 aKey
, nKeyLen
, nullptr, 0 )
1245 != rtl_Cipher_E_None
)
1247 return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1249 rtl_cipher_decodeARCFOUR( m_pData
->m_aCipher
,
1250 m_pData
->m_aOEntry
, 32,
1253 else if( m_pData
->m_nStandardRevision
== 3 )
1255 memcpy( nPwd
, m_pData
->m_aOEntry
, 32 );
1256 for( int i
= 19; i
>= 0; i
-- )
1258 sal_uInt8 nTempKey
[ENCRYPTION_KEY_LEN
];
1259 for( size_t j
= 0; j
< sizeof(nTempKey
); j
++ )
1260 nTempKey
[j
] = sal_uInt8(aKey
[j
] ^ i
);
1261 if (rtl_cipher_initARCFOUR( m_pData
->m_aCipher
, rtl_Cipher_DirectionDecode
,
1262 nTempKey
, nKeyLen
, nullptr, 0 )
1263 != rtl_Cipher_E_None
)
1265 return false; //TODO: differentiate "failed to decrypt" from "wrong password"
1267 rtl_cipher_decodeARCFOUR( m_pData
->m_aCipher
,
1269 nPwd
, 32 ); // decrypt inplace
1272 bValid
= check_user_password( OString( reinterpret_cast<char*>(nPwd
), 32 ), m_pData
.get() );
1278 PDFFileImplData
* PDFFile::impl_getData() const
1281 return m_pData
.get();
1282 m_pData
.reset( new PDFFileImplData
);
1283 // check for encryption dict in a trailer
1284 unsigned int nElements
= m_aSubElements
.size();
1285 while( nElements
-- > 0 )
1287 PDFTrailer
* pTrailer
= dynamic_cast<PDFTrailer
*>(m_aSubElements
[nElements
].get());
1288 if( pTrailer
&& pTrailer
->m_pDict
)
1291 PDFDict::Map::iterator doc_id
= pTrailer
->m_pDict
->m_aMap
.find( "ID"_ostr
);
1292 if( doc_id
!= pTrailer
->m_pDict
->m_aMap
.end() )
1294 PDFArray
* pArr
= dynamic_cast<PDFArray
*>(doc_id
->second
);
1295 if( pArr
&& !pArr
->m_aSubElements
.empty() )
1297 PDFString
* pStr
= dynamic_cast<PDFString
*>(pArr
->m_aSubElements
[0].get());
1299 m_pData
->m_aDocID
= pStr
->getFilteredString();
1300 #if OSL_DEBUG_LEVEL > 0
1301 OUStringBuffer aTmp
;
1302 for( int i
= 0; i
< m_pData
->m_aDocID
.getLength(); i
++ )
1303 aTmp
.append(static_cast<sal_Int32
>(sal_uInt8(m_pData
->m_aDocID
[i
])), 16);
1304 SAL_INFO("sdext.pdfimport.pdfparse", "DocId is <" << aTmp
.makeStringAndClear() << ">");
1308 // search Encrypt entry
1309 PDFDict::Map::iterator enc
=
1310 pTrailer
->m_pDict
->m_aMap
.find( "Encrypt"_ostr
);
1311 if( enc
!= pTrailer
->m_pDict
->m_aMap
.end() )
1313 PDFDict
* pDict
= dynamic_cast<PDFDict
*>(enc
->second
);
1316 PDFObjectRef
* pRef
= dynamic_cast<PDFObjectRef
*>(enc
->second
);
1319 PDFObject
* pObj
= findObject( pRef
);
1320 if( pObj
&& pObj
->m_pObject
)
1321 pDict
= dynamic_cast<PDFDict
*>(pObj
->m_pObject
);
1326 PDFDict::Map::iterator filter
= pDict
->m_aMap
.find( "Filter"_ostr
);
1327 PDFDict::Map::iterator version
= pDict
->m_aMap
.find( "V"_ostr
);
1328 PDFDict::Map::iterator len
= pDict
->m_aMap
.find( "Length"_ostr
);
1329 PDFDict::Map::iterator o_ent
= pDict
->m_aMap
.find( "O"_ostr
);
1330 PDFDict::Map::iterator u_ent
= pDict
->m_aMap
.find( "U"_ostr
);
1331 PDFDict::Map::iterator r_ent
= pDict
->m_aMap
.find( "R"_ostr
);
1332 PDFDict::Map::iterator p_ent
= pDict
->m_aMap
.find( "P"_ostr
);
1333 if( filter
!= pDict
->m_aMap
.end() )
1335 m_pData
->m_bIsEncrypted
= true;
1336 m_pData
->m_nKeyLength
= 5;
1337 if( version
!= pDict
->m_aMap
.end() )
1339 PDFNumber
* pNum
= dynamic_cast<PDFNumber
*>(version
->second
);
1341 m_pData
->m_nAlgoVersion
= static_cast<sal_uInt32
>(pNum
->m_fValue
);
1343 if( m_pData
->m_nAlgoVersion
>= 3 )
1344 m_pData
->m_nKeyLength
= 16;
1345 if( len
!= pDict
->m_aMap
.end() )
1347 PDFNumber
* pNum
= dynamic_cast<PDFNumber
*>(len
->second
);
1349 m_pData
->m_nKeyLength
= static_cast<sal_uInt32
>(pNum
->m_fValue
) / 8;
1351 PDFName
* pFilter
= dynamic_cast<PDFName
*>(filter
->second
);
1352 if( pFilter
&& pFilter
->getFilteredName() == "Standard" )
1353 m_pData
->m_bStandardHandler
= true;
1354 if( o_ent
!= pDict
->m_aMap
.end() )
1356 PDFString
* pString
= dynamic_cast<PDFString
*>(o_ent
->second
);
1359 OString aEnt
= pString
->getFilteredString();
1360 if( aEnt
.getLength() == 32 )
1361 memcpy( m_pData
->m_aOEntry
, aEnt
.getStr(), 32 );
1362 #if OSL_DEBUG_LEVEL > 0
1365 OUStringBuffer aTmp
;
1366 for( int i
= 0; i
< aEnt
.getLength(); i
++ )
1367 aTmp
.append(" " + OUString::number(sal_uInt8(aEnt
[i
]), 16));
1368 SAL_WARN("sdext.pdfimport.pdfparse",
1369 "O entry has length " << static_cast<int>(aEnt
.getLength()) << ", should be 32 <" << aTmp
.makeStringAndClear() << ">" );
1374 if( u_ent
!= pDict
->m_aMap
.end() )
1376 PDFString
* pString
= dynamic_cast<PDFString
*>(u_ent
->second
);
1379 OString aEnt
= pString
->getFilteredString();
1380 if( aEnt
.getLength() == 32 )
1381 memcpy( m_pData
->m_aUEntry
, aEnt
.getStr(), 32 );
1382 #if OSL_DEBUG_LEVEL > 0
1385 OUStringBuffer aTmp
;
1386 for( int i
= 0; i
< aEnt
.getLength(); i
++ )
1387 aTmp
.append(" " + OUString::number(sal_uInt8(aEnt
[i
]), 16));
1388 SAL_WARN("sdext.pdfimport.pdfparse",
1389 "U entry has length " << static_cast<int>(aEnt
.getLength()) << ", should be 32 <" << aTmp
.makeStringAndClear() << ">" );
1394 if( r_ent
!= pDict
->m_aMap
.end() )
1396 PDFNumber
* pNum
= dynamic_cast<PDFNumber
*>(r_ent
->second
);
1398 m_pData
->m_nStandardRevision
= static_cast<sal_uInt32
>(pNum
->m_fValue
);
1400 if( p_ent
!= pDict
->m_aMap
.end() )
1402 PDFNumber
* pNum
= dynamic_cast<PDFNumber
*>(p_ent
->second
);
1404 m_pData
->m_nPEntry
= static_cast<sal_uInt32
>(static_cast<sal_Int32
>(pNum
->m_fValue
));
1405 SAL_INFO("sdext.pdfimport.pdfparse", "p entry is " << m_pData
->m_nPEntry
);
1408 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
);
1416 return m_pData
.get();
1419 bool PDFFile::emit( EmitContext
& rWriteContext
) const
1421 setEmitData( rWriteContext
, new EmitImplData( this ) );
1425 OString::number( sal_Int32( m_nMajor
) ) +
1427 OString::number( sal_Int32( m_nMinor
) ) +
1429 if( ! rWriteContext
.write( aBuf
.getStr(), aBuf
.getLength() ) )
1431 return emitSubElements( rWriteContext
);
1434 PDFEntry
* PDFFile::clone() const
1436 PDFFile
* pNewFl
= new PDFFile();
1437 pNewFl
->m_nMajor
= m_nMajor
;
1438 pNewFl
->m_nMinor
= m_nMinor
;
1439 cloneSubElements( pNewFl
->m_aSubElements
);
1447 bool PDFPart::emit( EmitContext
& rWriteContext
) const
1449 return emitSubElements( rWriteContext
);
1452 PDFEntry
* PDFPart::clone() const
1454 PDFPart
* pNewPt
= new PDFPart();
1455 cloneSubElements( pNewPt
->m_aSubElements
);
1459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */