LCOV - code coverage report
Current view: top level - libreoffice/sdext/source/pdfimport/pdfparse - pdfentries.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 102 796 12.8 %
Date: 2012-12-17 Functions: 35 95 36.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10