LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/package/source/zipapi - ZipFile.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 213 534 39.9 %
Date: 2013-07-09 Functions: 16 24 66.7 %
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 <com/sun/star/lang/XMultiServiceFactory.hpp>
      22             : #include <com/sun/star/ucb/XProgressHandler.hpp>
      23             : #include <com/sun/star/packages/zip/ZipConstants.hpp>
      24             : #include <com/sun/star/xml/crypto/XCipherContext.hpp>
      25             : #include <com/sun/star/xml/crypto/XDigestContext.hpp>
      26             : #include <com/sun/star/xml/crypto/XCipherContextSupplier.hpp>
      27             : #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp>
      28             : #include <com/sun/star/xml/crypto/CipherID.hpp>
      29             : #include <com/sun/star/xml/crypto/DigestID.hpp>
      30             : #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
      31             : 
      32             : #include <comphelper/storagehelper.hxx>
      33             : #include <comphelper/processfactory.hxx>
      34             : #include <rtl/digest.h>
      35             : 
      36             : #include <vector>
      37             : 
      38             : #include "blowfishcontext.hxx"
      39             : #include "sha1context.hxx"
      40             : #include <ZipFile.hxx>
      41             : #include <ZipEnumeration.hxx>
      42             : #include <XUnbufferedStream.hxx>
      43             : #include <PackageConstants.hxx>
      44             : #include <EncryptedDataHeader.hxx>
      45             : #include <EncryptionData.hxx>
      46             : #include <MemoryByteGrabber.hxx>
      47             : 
      48             : #include <CRC32.hxx>
      49             : 
      50             : using namespace com::sun::star;
      51             : using namespace com::sun::star::io;
      52             : using namespace com::sun::star::uno;
      53             : using namespace com::sun::star::ucb;
      54             : using namespace com::sun::star::lang;
      55             : using namespace com::sun::star::packages;
      56             : using namespace com::sun::star::packages::zip;
      57             : using namespace com::sun::star::packages::zip::ZipConstants;
      58             : 
      59             : using ZipUtils::Inflater;
      60             : 
      61             : /** This class is used to read entries from a zip file
      62             :  */
      63         240 : ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XComponentContext > & rxContext, sal_Bool bInitialise )
      64             :     throw(IOException, ZipException, RuntimeException)
      65             : : aGrabber(xInput)
      66             : , aInflater (sal_True)
      67             : , xStream(xInput)
      68             : , xSeek(xInput, UNO_QUERY)
      69             : , m_xContext ( rxContext )
      70         240 : , bRecoveryMode( sal_False )
      71             : {
      72         240 :     if (bInitialise)
      73             :     {
      74          35 :         if ( readCEN() == -1 )
      75             :         {
      76           0 :             aEntries.clear();
      77           0 :             throw ZipException( "stream data looks to be broken", uno::Reference < XInterface > () );
      78             :         }
      79             :     }
      80         240 : }
      81             : 
      82             : 
      83             : 
      84        1273 : ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XComponentContext > & rxContext, sal_Bool bInitialise, sal_Bool bForceRecovery, uno::Reference < XProgressHandler > xProgress )
      85             :     throw(IOException, ZipException, RuntimeException)
      86             : : aGrabber(xInput)
      87             : , aInflater (sal_True)
      88             : , xStream(xInput)
      89             : , xSeek(xInput, UNO_QUERY)
      90             : , m_xContext ( rxContext )
      91             : , xProgressHandler( xProgress )
      92        1273 : , bRecoveryMode( bForceRecovery )
      93             : {
      94        1273 :     if (bInitialise)
      95             :     {
      96        1273 :         if ( bForceRecovery )
      97             :         {
      98           0 :             recover();
      99             :         }
     100        1273 :         else if ( readCEN() == -1 )
     101             :         {
     102           0 :             aEntries.clear();
     103           0 :             throw ZipException("stream data looks to be broken", uno::Reference < XInterface > () );
     104             :         }
     105             :     }
     106        1273 : }
     107             : 
     108        2966 : ZipFile::~ZipFile()
     109             : {
     110        1483 :     aEntries.clear();
     111        1483 : }
     112             : 
     113          24 : void ZipFile::setInputStream ( uno::Reference < XInputStream > xNewStream )
     114             : {
     115          24 :     ::osl::MutexGuard aGuard( m_aMutex );
     116             : 
     117          24 :     xStream = xNewStream;
     118          24 :     xSeek = uno::Reference < XSeekable > ( xStream, UNO_QUERY );
     119          24 :     aGrabber.setInputStream ( xStream );
     120          24 : }
     121             : 
     122          18 : uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData )
     123             : {
     124          18 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext;
     125          18 :     if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA256_1K )
     126             :     {
     127          14 :         uno::Reference< uno::XComponentContext > xContext = xArgContext;
     128          14 :         if ( !xContext.is() )
     129           0 :             xContext = comphelper::getProcessComponentContext();
     130             : 
     131          28 :         uno::Reference< xml::crypto::XNSSInitializer > xDigestContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     132             : 
     133          28 :         xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW );
     134             :     }
     135           4 :     else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K )
     136           4 :         xDigestContext.set( SHA1DigestContext::Create(), uno::UNO_SET_THROW );
     137             : 
     138          18 :     return xDigestContext;
     139             : }
     140             : 
     141          31 : uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt )
     142             : {
     143          31 :     uno::Reference< xml::crypto::XCipherContext > xResult;
     144             : 
     145             :     try
     146             :     {
     147          31 :         if (xEncryptionData->m_nDerivedKeySize < 0)
     148             :         {
     149             :             throw ZipIOException("Invalid derived key length!",
     150           0 :                                   uno::Reference< XInterface >() );
     151             :         }
     152             : 
     153          31 :         uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize );
     154          62 :         if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ),
     155          31 :                             aDerivedKey.getLength(),
     156          31 :                             reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ),
     157          31 :                             xEncryptionData->m_aKey.getLength(),
     158          31 :                             reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ),
     159          31 :                             xEncryptionData->m_aSalt.getLength(),
     160         155 :                             xEncryptionData->m_nIterationCount ) )
     161             :         {
     162             :             throw ZipIOException("Can not create derived key!",
     163           0 :                                   uno::Reference< XInterface >() );
     164             :         }
     165             : 
     166          31 :         if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
     167             :         {
     168          23 :             uno::Reference< uno::XComponentContext > xContext = xArgContext;
     169          23 :             if ( !xContext.is() )
     170           0 :                 xContext = comphelper::getProcessComponentContext();
     171             : 
     172          46 :             uno::Reference< xml::crypto::XNSSInitializer > xCipherContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     173             : 
     174          46 :             xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() );
     175             :         }
     176           8 :         else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 )
     177             :         {
     178           8 :             xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt );
     179             :         }
     180             :         else
     181             :         {
     182             :             throw ZipIOException("Unknown cipher algorithm is requested!",
     183           0 :                                   uno::Reference< XInterface >() );
     184          31 :         }
     185             :     }
     186           0 :     catch( ... )
     187             :     {
     188             :         OSL_ENSURE( sal_False, "Can not create cipher context!" );
     189             :     }
     190             : 
     191          31 :     return xResult;
     192             : }
     193             : 
     194           0 : void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData,
     195             :                                 sal_Int64 nSize,
     196             :                                 const OUString& aMediaType,
     197             :                                 sal_Int8 * & pHeader )
     198             : {
     199             :     // I think it's safe to restrict vector and salt length to 2 bytes !
     200           0 :     sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() );
     201           0 :     sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() );
     202           0 :     sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() );
     203           0 :     sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) );
     204             : 
     205             :     // First the header
     206           0 :     *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF;
     207           0 :     *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF;
     208           0 :     *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF;
     209           0 :     *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF;
     210             : 
     211             :     // Then the version
     212           0 :     *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF;
     213           0 :     *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF;
     214             : 
     215             :     // Then the iteration Count
     216           0 :     sal_Int32 nIterationCount = rData->m_nIterationCount;
     217           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF);
     218           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF);
     219           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF);
     220           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF);
     221             : 
     222             :     // FIXME64: need to handle larger sizes
     223             :     // Then the size:
     224           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF);
     225           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF);
     226           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF);
     227           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF);
     228             : 
     229             :     // Then the encryption algorithm
     230           0 :     sal_Int32 nEncAlgID = rData->m_nEncAlg;
     231           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF);
     232           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF);
     233           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF);
     234           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF);
     235             : 
     236             :     // Then the checksum algorithm
     237           0 :     sal_Int32 nChecksumAlgID = rData->m_nCheckAlg;
     238           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF);
     239           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF);
     240           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF);
     241           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF);
     242             : 
     243             :     // Then the derived key size
     244           0 :     sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize;
     245           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF);
     246           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF);
     247           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF);
     248           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF);
     249             : 
     250             :     // Then the start key generation algorithm
     251           0 :     sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID;
     252           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF);
     253           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF);
     254           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF);
     255           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF);
     256             : 
     257             :     // Then the salt length
     258           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF);
     259           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF);
     260             : 
     261             :     // Then the IV length
     262           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF);
     263           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF);
     264             : 
     265             :     // Then the digest length
     266           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF);
     267           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF);
     268             : 
     269             :     // Then the mediatype length
     270           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF);
     271           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF);
     272             : 
     273             :     // Then the salt content
     274           0 :     memcpy ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength );
     275           0 :     pHeader += nSaltLength;
     276             : 
     277             :     // Then the IV content
     278           0 :     memcpy ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength );
     279           0 :     pHeader += nIVLength;
     280             : 
     281             :     // Then the digest content
     282           0 :     memcpy ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength );
     283           0 :     pHeader += nDigestLength;
     284             : 
     285             :     // Then the mediatype itself
     286           0 :     memcpy ( pHeader, aMediaType.getStr(), nMediaTypeLength );
     287           0 :     pHeader += nMediaTypeLength;
     288           0 : }
     289             : 
     290           0 : sal_Bool ZipFile::StaticFillData (  ::rtl::Reference< BaseEncryptionData > & rData,
     291             :                                     sal_Int32 &rEncAlg,
     292             :                                     sal_Int32 &rChecksumAlg,
     293             :                                     sal_Int32 &rDerivedKeySize,
     294             :                                     sal_Int32 &rStartKeyGenID,
     295             :                                     sal_Int32 &rSize,
     296             :                                     OUString& aMediaType,
     297             :                                     const uno::Reference< XInputStream >& rStream )
     298             : {
     299           0 :     sal_Bool bOk = sal_False;
     300           0 :     const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4;
     301           0 :     Sequence < sal_Int8 > aBuffer ( nHeaderSize );
     302           0 :     if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) )
     303             :     {
     304           0 :         sal_Int16 nPos = 0;
     305           0 :         sal_Int8 *pBuffer = aBuffer.getArray();
     306           0 :         sal_Int16 nVersion = pBuffer[nPos++] & 0xFF;
     307           0 :         nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8;
     308           0 :         if ( nVersion == n_ConstCurrentVersion )
     309             :         {
     310           0 :             sal_Int32 nCount = pBuffer[nPos++] & 0xFF;
     311           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 8;
     312           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 16;
     313           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 24;
     314           0 :             rData->m_nIterationCount = nCount;
     315             : 
     316           0 :             rSize  =   pBuffer[nPos++] & 0xFF;
     317           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 8;
     318           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 16;
     319           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 24;
     320             : 
     321           0 :             rEncAlg   =   pBuffer[nPos++] & 0xFF;
     322           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     323           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     324           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     325             : 
     326           0 :             rChecksumAlg   =   pBuffer[nPos++] & 0xFF;
     327           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     328           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     329           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     330             : 
     331           0 :             rDerivedKeySize   =   pBuffer[nPos++] & 0xFF;
     332           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     333           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     334           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     335             : 
     336           0 :             rStartKeyGenID   =   pBuffer[nPos++] & 0xFF;
     337           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     338           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     339           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     340             : 
     341           0 :             sal_Int16 nSaltLength =   pBuffer[nPos++] & 0xFF;
     342           0 :             nSaltLength          |= ( pBuffer[nPos++] & 0xFF ) << 8;
     343           0 :             sal_Int16 nIVLength   = ( pBuffer[nPos++] & 0xFF );
     344           0 :             nIVLength            |= ( pBuffer[nPos++] & 0xFF ) << 8;
     345           0 :             sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF;
     346           0 :             nDigestLength        |= ( pBuffer[nPos++] & 0xFF ) << 8;
     347             : 
     348           0 :             sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF;
     349           0 :             nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
     350             : 
     351           0 :             if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) )
     352             :             {
     353           0 :                 rData->m_aSalt.realloc ( nSaltLength );
     354           0 :                 memcpy ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength );
     355           0 :                 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) )
     356             :                 {
     357           0 :                     rData->m_aInitVector.realloc ( nIVLength );
     358           0 :                     memcpy ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength );
     359           0 :                     if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) )
     360             :                     {
     361           0 :                         rData->m_aDigest.realloc ( nDigestLength );
     362           0 :                         memcpy ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength );
     363             : 
     364           0 :                         if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) )
     365             :                         {
     366           0 :                             aMediaType = OUString( (sal_Unicode*)aBuffer.getConstArray(),
     367           0 :                                                             nMediaTypeLength / sizeof( sal_Unicode ) );
     368           0 :                             bOk = sal_True;
     369             :                         }
     370             :                     }
     371             :                 }
     372             :             }
     373             :         }
     374             :     }
     375           0 :     return bOk;
     376             : }
     377             : 
     378           0 : uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const uno::Reference< uno::XComponentContext >& rxContext,
     379             :                                                                 const uno::Reference< XInputStream >& xStream,
     380             :                                                                 const ::rtl::Reference< EncryptionData > &rData )
     381             :         throw ( packages::WrongPasswordException, ZipIOException, RuntimeException )
     382             : {
     383           0 :     if ( !rData.is() )
     384             :         throw ZipIOException("Encrypted stream without encryption data!\n",
     385           0 :                             uno::Reference< XInterface >() );
     386             : 
     387           0 :     if ( !rData->m_aKey.getLength() )
     388           0 :         throw packages::WrongPasswordException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     389             : 
     390           0 :     uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY );
     391           0 :     if ( !xSeek.is() )
     392             :         throw ZipIOException("The stream must be seekable!\n",
     393           0 :                             uno::Reference< XInterface >() );
     394             : 
     395             : 
     396             :     // if we have a digest, then this file is an encrypted one and we should
     397             :     // check if we can decrypt it or not
     398             :     OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     399           0 :     if ( rData->m_aDigest.getLength() )
     400             :     {
     401           0 :         sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() );
     402           0 :         if ( nSize > n_ConstDigestLength + 32 )
     403           0 :             nSize = n_ConstDigestLength + 32;
     404             : 
     405             :         // skip header
     406           0 :         xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() +
     407           0 :                                 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() );
     408             : 
     409             :         // Only want to read enough to verify the digest
     410           0 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     411             : 
     412           0 :         xStream->readBytes( aReadBuffer, nSize );
     413             : 
     414           0 :         if ( !StaticHasValidPassword( rxContext, aReadBuffer, rData ) )
     415           0 :             throw packages::WrongPasswordException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     416             :     }
     417             : 
     418           0 :     return new XUnbufferedStream( rxContext, xStream, rData );
     419             : }
     420             : 
     421             : #if 0
     422             : // for debugging purposes
     423             : void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence )
     424             : {
     425             :     if ( aSequence.getLength() )
     426             :     {
     427             :         sal_Int32* pPointer = *( (sal_Int32**)&aSequence );
     428             :         sal_Int32 nSize = *( pPointer + 1 );
     429             :         sal_Int32 nMemSize = *( pPointer - 2 );
     430             :         sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) );
     431             :         OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" );
     432             :     }
     433             : }
     434             : #endif
     435             : 
     436          13 : sal_Bool ZipFile::StaticHasValidPassword( const uno::Reference< uno::XComponentContext >& rxContext, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData )
     437             : {
     438          13 :     if ( !rData.is() || !rData->m_aKey.getLength() )
     439           0 :         return sal_False;
     440             : 
     441          13 :     sal_Bool bRet = sal_False;
     442             : 
     443          13 :     uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( rxContext, rData, false ), uno::UNO_SET_THROW );
     444             : 
     445          26 :     uno::Sequence< sal_Int8 > aDecryptBuffer;
     446          26 :     uno::Sequence< sal_Int8 > aDecryptBuffer2;
     447             :     try
     448             :     {
     449          13 :         aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer );
     450          13 :         aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose();
     451             :     }
     452           7 :     catch( uno::Exception& )
     453             :     {
     454             :         // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream
     455             :         // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks )
     456             :     }
     457             : 
     458          13 :     if ( aDecryptBuffer2.getLength() )
     459             :     {
     460           2 :         sal_Int32 nOldLen = aDecryptBuffer.getLength();
     461           2 :         aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() );
     462           2 :         memcpy( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() );
     463             :     }
     464             : 
     465          13 :     if ( aDecryptBuffer.getLength() > n_ConstDigestLength )
     466          10 :         aDecryptBuffer.realloc( n_ConstDigestLength );
     467             : 
     468          26 :     uno::Sequence< sal_Int8 > aDigestSeq;
     469          26 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( rxContext, rData ), uno::UNO_SET_THROW );
     470             : 
     471          13 :     xDigestContext->updateDigest( aDecryptBuffer );
     472          13 :     aDigestSeq = xDigestContext->finalizeDigestAndDispose();
     473             : 
     474             :     // If we don't have a digest, then we have to assume that the password is correct
     475          26 :     if (  rData->m_aDigest.getLength() != 0  &&
     476          26 :           ( aDigestSeq.getLength() != rData->m_aDigest.getLength() ||
     477          13 :             0 != memcmp ( aDigestSeq.getConstArray(),
     478          13 :                                      rData->m_aDigest.getConstArray(),
     479          26 :                                     aDigestSeq.getLength() ) ) )
     480             :     {
     481             :         // We should probably tell the user that the password they entered was wrong
     482             :     }
     483             :     else
     484          13 :         bRet = sal_True;
     485             : 
     486          26 :     return bRet;
     487             : }
     488             : 
     489          13 : sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< EncryptionData >& rData )
     490             : {
     491          13 :     ::osl::MutexGuard aGuard( m_aMutex );
     492             : 
     493          13 :     sal_Bool bRet = sal_False;
     494          13 :     if ( rData.is() && rData->m_aKey.getLength() )
     495             :     {
     496          13 :         xSeek->seek( rEntry.nOffset );
     497          13 :         sal_Int64 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize;
     498             : 
     499             :         // Only want to read enough to verify the digest
     500          13 :         if ( nSize > n_ConstDigestDecrypt )
     501           9 :             nSize = n_ConstDigestDecrypt;
     502             : 
     503          13 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     504             : 
     505          13 :         xStream->readBytes( aReadBuffer, nSize );
     506             : 
     507          13 :         bRet = StaticHasValidPassword( m_xContext, aReadBuffer, rData );
     508             :     }
     509             : 
     510          13 :     return bRet;
     511             : }
     512             : 
     513        8774 : uno::Reference< XInputStream > ZipFile::createUnbufferedStream(
     514             :             SotMutexHolderRef aMutexHolder,
     515             :             ZipEntry & rEntry,
     516             :             const ::rtl::Reference< EncryptionData > &rData,
     517             :             sal_Int8 nStreamMode,
     518             :             sal_Bool bIsEncrypted,
     519             :             OUString aMediaType )
     520             : {
     521        8774 :     ::osl::MutexGuard aGuard( m_aMutex );
     522             : 
     523        8774 :     return new XUnbufferedStream ( m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode );
     524             : }
     525             : 
     526             : 
     527        1273 : ZipEnumeration * SAL_CALL ZipFile::entries(  )
     528             : {
     529        1273 :     return new ZipEnumeration ( aEntries );
     530             : }
     531             : 
     532        1061 : uno::Reference< XInputStream > SAL_CALL ZipFile::getInputStream( ZipEntry& rEntry,
     533             :         const ::rtl::Reference< EncryptionData > &rData,
     534             :         sal_Bool bIsEncrypted,
     535             :         SotMutexHolderRef aMutexHolder )
     536             :     throw(IOException, ZipException, RuntimeException)
     537             : {
     538        1061 :     ::osl::MutexGuard aGuard( m_aMutex );
     539             : 
     540        1061 :     if ( rEntry.nOffset <= 0 )
     541        1061 :         readLOC( rEntry );
     542             : 
     543             :     // We want to return a rawStream if we either don't have a key or if the
     544             :     // key is wrong
     545             : 
     546        1061 :     sal_Bool bNeedRawStream = rEntry.nMethod == STORED;
     547             : 
     548             :     // if we have a digest, then this file is an encrypted one and we should
     549             :     // check if we can decrypt it or not
     550        1061 :     if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() )
     551           0 :         bNeedRawStream = !hasValidPassword ( rEntry, rData );
     552             : 
     553             :     return createUnbufferedStream ( aMutexHolder,
     554             :                                     rEntry,
     555             :                                     rData,
     556             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     557        1061 :                                     bIsEncrypted );
     558             : }
     559             : 
     560        7619 : uno::Reference< XInputStream > SAL_CALL ZipFile::getDataStream( ZipEntry& rEntry,
     561             :         const ::rtl::Reference< EncryptionData > &rData,
     562             :         sal_Bool bIsEncrypted,
     563             :         SotMutexHolderRef aMutexHolder )
     564             :     throw ( packages::WrongPasswordException,
     565             :             IOException,
     566             :             ZipException,
     567             :             RuntimeException )
     568             : {
     569        7619 :     ::osl::MutexGuard aGuard( m_aMutex );
     570             : 
     571        7619 :     if ( rEntry.nOffset <= 0 )
     572        6730 :         readLOC( rEntry );
     573             : 
     574             :     // An exception must be thrown in case stream is encrypted and
     575             :     // there is no key or the key is wrong
     576        7619 :     sal_Bool bNeedRawStream = sal_False;
     577        7619 :     if ( bIsEncrypted )
     578             :     {
     579             :         // in case no digest is provided there is no way
     580             :         // to detect password correctness
     581          13 :         if ( !rData.is() )
     582             :             throw ZipException("Encrypted stream without encryption data!\n",
     583           0 :                                 uno::Reference< XInterface >() );
     584             : 
     585             :         // if we have a digest, then this file is an encrypted one and we should
     586             :         // check if we can decrypt it or not
     587             :         OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     588          13 :         if ( rData->m_aDigest.getLength() && !hasValidPassword ( rEntry, rData ) )
     589           0 :                 throw packages::WrongPasswordException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     590             :     }
     591             :     else
     592        7606 :         bNeedRawStream = ( rEntry.nMethod == STORED );
     593             : 
     594             :     return createUnbufferedStream ( aMutexHolder,
     595             :                                     rEntry,
     596             :                                     rData,
     597             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     598        7619 :                                     bIsEncrypted );
     599             : }
     600             : 
     601          94 : uno::Reference< XInputStream > SAL_CALL ZipFile::getRawData( ZipEntry& rEntry,
     602             :         const ::rtl::Reference< EncryptionData >& rData,
     603             :         sal_Bool bIsEncrypted,
     604             :         SotMutexHolderRef aMutexHolder )
     605             :     throw(IOException, ZipException, RuntimeException)
     606             : {
     607          94 :     ::osl::MutexGuard aGuard( m_aMutex );
     608             : 
     609          94 :     if ( rEntry.nOffset <= 0 )
     610          47 :         readLOC( rEntry );
     611             : 
     612          94 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted );
     613             : }
     614             : 
     615           0 : uno::Reference< XInputStream > SAL_CALL ZipFile::getWrappedRawStream(
     616             :         ZipEntry& rEntry,
     617             :         const ::rtl::Reference< EncryptionData >& rData,
     618             :         const OUString& aMediaType,
     619             :         SotMutexHolderRef aMutexHolder )
     620             :     throw ( packages::NoEncryptionException,
     621             :             IOException,
     622             :             ZipException,
     623             :             RuntimeException )
     624             : {
     625           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     626             : 
     627           0 :     if ( !rData.is() )
     628           0 :         throw packages::NoEncryptionException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     629             : 
     630           0 :     if ( rEntry.nOffset <= 0 )
     631           0 :         readLOC( rEntry );
     632             : 
     633           0 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType );
     634             : }
     635             : 
     636        7838 : sal_Bool ZipFile::readLOC( ZipEntry &rEntry )
     637             :     throw(IOException, ZipException, RuntimeException)
     638             : {
     639        7838 :     ::osl::MutexGuard aGuard( m_aMutex );
     640             : 
     641             :     sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize;
     642             :     sal_Int16 nVersion, nFlag, nHow, nPathLen, nExtraLen;
     643        7838 :     sal_Int64 nPos = -rEntry.nOffset;
     644             : 
     645        7838 :     aGrabber.seek(nPos);
     646        7838 :     aGrabber >> nTestSig;
     647             : 
     648        7838 :     if (nTestSig != LOCSIG)
     649           0 :         throw ZipIOException("Invalid LOC header (bad signature)", uno::Reference < XInterface > () );
     650        7838 :     aGrabber >> nVersion;
     651        7838 :     aGrabber >> nFlag;
     652        7838 :     aGrabber >> nHow;
     653        7838 :     aGrabber >> nTime;
     654        7838 :     aGrabber >> nCRC;
     655        7838 :     aGrabber >> nCompressedSize;
     656        7838 :     aGrabber >> nSize;
     657        7838 :     aGrabber >> nPathLen;
     658        7838 :     aGrabber >> nExtraLen;
     659        7838 :     rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
     660             : 
     661             :     // FIXME64: need to read 64bit LOC
     662             : 
     663        7838 :     sal_Bool bBroken = sal_False;
     664             : 
     665             :     try
     666             :     {
     667             :         // read always in UTF8, some tools seem not to set UTF8 bit
     668        7838 :         uno::Sequence < sal_Int8 > aNameBuffer( nPathLen );
     669        7838 :         sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen );
     670        7838 :         if ( nRead < aNameBuffer.getLength() )
     671           0 :                 aNameBuffer.realloc( nRead );
     672             : 
     673        7838 :         OUString sLOCPath = OUString::intern( (sal_Char *) aNameBuffer.getArray(),
     674             :                                                           aNameBuffer.getLength(),
     675       23514 :                                                           RTL_TEXTENCODING_UTF8 );
     676             : 
     677        7838 :         if ( rEntry.nPathLen == -1 ) // the file was created
     678             :         {
     679           0 :             rEntry.nPathLen = nPathLen;
     680           0 :             rEntry.sPath = sLOCPath;
     681             :         }
     682             : 
     683             :         // check basic local file header / entry consistency, just
     684             :         // plain ignore bits 1 & 2 of the flag field - they are either
     685             :         // purely informative, or even fully undefined (depending on
     686             :         // nMethod)
     687             :         // Do *not* compare nMethod / nHow, older versions with
     688             :         // encrypted streams write mismatching DEFLATE/STORE pairs
     689             :         // there.
     690             :         // Do *not* compare timestamps, since MSO 2010 can produce documents
     691             :         // with timestamp difference in the central directory entry and local
     692             :         // file header.
     693        7838 :         bBroken = rEntry.nVersion != nVersion
     694        7838 :                         || rEntry.nPathLen != nPathLen
     695       23514 :                         || !rEntry.sPath.equals( sLOCPath );
     696             :     }
     697           0 :     catch(...)
     698             :     {
     699           0 :         bBroken = sal_True;
     700             :     }
     701             : 
     702        7838 :     if ( bBroken && !bRecoveryMode )
     703             :         throw ZipIOException("The stream seems to be broken!",
     704           0 :                             uno::Reference< XInterface >() );
     705             : 
     706        7838 :     return sal_True;
     707             : }
     708             : 
     709        1308 : sal_Int32 ZipFile::findEND( )
     710             :     throw(IOException, ZipException, RuntimeException)
     711             : {
     712             :     // this method is called in constructor only, no need for mutex
     713             :     sal_Int32 nLength, nPos, nEnd;
     714        1308 :     Sequence < sal_Int8 > aBuffer;
     715             :     try
     716             :     {
     717        1308 :         nLength = static_cast <sal_Int32 > (aGrabber.getLength());
     718        1308 :         if (nLength == 0 || nLength < ENDHDR)
     719           0 :             return -1;
     720        1308 :         nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
     721        1308 :         nEnd = nPos >= 0 ? nPos : 0 ;
     722             : 
     723        1308 :         aGrabber.seek( nEnd );
     724        1308 :         aGrabber.readBytes ( aBuffer, nLength - nEnd );
     725             : 
     726        1308 :         const sal_Int8 *pBuffer = aBuffer.getConstArray();
     727             : 
     728        1308 :         nPos = nLength - nEnd - ENDHDR;
     729        2616 :         while ( nPos >= 0 )
     730             :         {
     731        1308 :             if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
     732        1308 :                 return nPos + nEnd;
     733           0 :             nPos--;
     734             :         }
     735             :     }
     736           0 :     catch ( IllegalArgumentException& )
     737             :     {
     738           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     739             :     }
     740           0 :     catch ( NotConnectedException& )
     741             :     {
     742           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     743             :     }
     744           0 :     catch ( BufferSizeExceededException& )
     745             :     {
     746           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     747             :     }
     748           0 :     throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     749             : }
     750             : 
     751        1308 : sal_Int32 ZipFile::readCEN()
     752             :     throw(IOException, ZipException, RuntimeException)
     753             : {
     754             :     // this method is called in constructor only, no need for mutex
     755        1308 :     sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos;
     756             :     sal_uInt16 nCount, nTotal;
     757             : 
     758             :     try
     759             :     {
     760        1308 :         nEndPos = findEND();
     761        1308 :         if (nEndPos == -1)
     762           0 :             return -1;
     763        1308 :         aGrabber.seek(nEndPos + ENDTOT);
     764        1308 :         aGrabber >> nTotal;
     765        1308 :         aGrabber >> nCenLen;
     766        1308 :         aGrabber >> nCenOff;
     767             : 
     768        1308 :         if ( nTotal * CENHDR > nCenLen )
     769           0 :             throw ZipException("invalid END header (bad entry count)", uno::Reference < XInterface > () );
     770             : 
     771        1308 :         if ( nTotal > ZIP_MAXENTRIES )
     772           0 :             throw ZipException("too many entries in ZIP File", uno::Reference < XInterface > () );
     773             : 
     774        1308 :         if ( nCenLen < 0 || nCenLen > nEndPos )
     775           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     776             : 
     777        1308 :         nCenPos = nEndPos - nCenLen;
     778             : 
     779        1308 :         if ( nCenOff < 0 || nCenOff > nCenPos )
     780           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     781             : 
     782        1308 :         nLocPos = nCenPos - nCenOff;
     783        1308 :         aGrabber.seek( nCenPos );
     784        1308 :         Sequence < sal_Int8 > aCENBuffer ( nCenLen );
     785        1308 :         sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
     786        1308 :         if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
     787           0 :             throw ZipException ("Error reading CEN into memory buffer!", uno::Reference < XInterface > () );
     788             : 
     789        2616 :         MemoryByteGrabber aMemGrabber ( aCENBuffer );
     790             : 
     791        2616 :         ZipEntry aEntry;
     792             :         sal_Int32 nTestSig;
     793             :         sal_Int16 nCommentLen;
     794             : 
     795      139073 :         for (nCount = 0 ; nCount < nTotal; nCount++)
     796             :         {
     797      137765 :             aMemGrabber >> nTestSig;
     798      137765 :             if ( nTestSig != CENSIG )
     799           0 :                 throw ZipException("Invalid CEN header (bad signature)", uno::Reference < XInterface > () );
     800             : 
     801      137765 :             aMemGrabber.skipBytes ( 2 );
     802      137765 :             aMemGrabber >> aEntry.nVersion;
     803             : 
     804      137765 :             if ( ( aEntry.nVersion & 1 ) == 1 )
     805           0 :                 throw ZipException("Invalid CEN header (encrypted entry)", uno::Reference < XInterface > () );
     806             : 
     807      137765 :             aMemGrabber >> aEntry.nFlag;
     808      137765 :             aMemGrabber >> aEntry.nMethod;
     809             : 
     810      137765 :             if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED)
     811           0 :                 throw ZipException("Invalid CEN header (bad compression method)", uno::Reference < XInterface > () );
     812             : 
     813      137765 :             aMemGrabber >> aEntry.nTime;
     814      137765 :             aMemGrabber >> aEntry.nCrc;
     815             : 
     816             :             sal_uInt32 nCompressedSize, nSize, nOffset;
     817             : 
     818      137765 :             aMemGrabber >> nCompressedSize;
     819      137765 :             aMemGrabber >> nSize;
     820      137765 :             aMemGrabber >> aEntry.nPathLen;
     821      137765 :             aMemGrabber >> aEntry.nExtraLen;
     822      137765 :             aMemGrabber >> nCommentLen;
     823      137765 :             aMemGrabber.skipBytes ( 8 );
     824      137765 :             aMemGrabber >> nOffset;
     825             : 
     826             :             // FIXME64: need to read the 64bit header instead
     827      275530 :             if ( nSize == 0xffffffff ||
     828      275530 :                  nOffset == 0xffffffff ||
     829      137765 :                  nCompressedSize == 0xffffffff ) {
     830           0 :                 throw ZipException("PK64 zip file entry", uno::Reference < XInterface > () );
     831             :             } else {
     832      137765 :                 aEntry.nCompressedSize = nCompressedSize;
     833      137765 :                 aEntry.nSize = nSize;
     834      137765 :                 aEntry.nOffset = nOffset;
     835             :             }
     836             : 
     837      137765 :             aEntry.nOffset += nLocPos;
     838      137765 :             aEntry.nOffset *= -1;
     839             : 
     840      137765 :             if ( aEntry.nPathLen < 0 )
     841           0 :                 throw ZipException("unexpected name length", uno::Reference < XInterface > () );
     842             : 
     843      137765 :             if ( nCommentLen < 0 )
     844           0 :                 throw ZipException("unexpected comment length", uno::Reference < XInterface > () );
     845             : 
     846      137765 :             if ( aEntry.nExtraLen < 0 )
     847           0 :                 throw ZipException("unexpected extra header info length", uno::Reference < XInterface > () );
     848             : 
     849             :             // read always in UTF8, some tools seem not to set UTF8 bit
     850      275530 :             aEntry.sPath = OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(),
     851             :                                                    aEntry.nPathLen,
     852      137765 :                                                    RTL_TEXTENCODING_UTF8 );
     853             : 
     854      137765 :             if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, sal_True ) )
     855           0 :                 throw ZipException("Zip entry has an invalid name.", uno::Reference < XInterface > () );
     856             : 
     857      137765 :             aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen );
     858      137765 :             aEntries[aEntry.sPath] = aEntry;
     859             :         }
     860             : 
     861        1308 :         if (nCount != nTotal)
     862        1308 :             throw ZipException("Count != Total", uno::Reference < XInterface > () );
     863             :     }
     864           0 :     catch ( IllegalArgumentException & )
     865             :     {
     866             :         // seek can throw this...
     867           0 :         nCenPos = -1; // make sure we return -1 to indicate an error
     868             :     }
     869        1308 :     return nCenPos;
     870             : }
     871             : 
     872           0 : sal_Int32 ZipFile::recover()
     873             :     throw(IOException, ZipException, RuntimeException)
     874             : {
     875           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     876             : 
     877             :     sal_Int64 nLength;
     878           0 :     Sequence < sal_Int8 > aBuffer;
     879           0 :     Sequence < sal_Int32 > aHeaderOffsets;
     880             : 
     881             :     try
     882             :     {
     883           0 :         nLength = aGrabber.getLength();
     884           0 :         if (nLength == 0 || nLength < ENDHDR)
     885           0 :             return -1;
     886             : 
     887           0 :         aGrabber.seek( 0 );
     888             : 
     889           0 :         const sal_Int64 nToRead = 32000;
     890           0 :         for( sal_Int64 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; )
     891             :         {
     892           0 :             const sal_Int8 *pBuffer = aBuffer.getConstArray();
     893           0 :             sal_Int32 nBufSize = aBuffer.getLength();
     894             : 
     895           0 :             sal_Int64 nPos = 0;
     896             :             // the buffer should contain at least one header,
     897             :             // or if it is end of the file, at least the postheader with sizes and hash
     898           0 :             while( nPos < nBufSize - 30
     899           0 :                 || ( nBufSize < nToRead && nPos < nBufSize - 16 ) )
     900             : 
     901             :             {
     902           0 :                 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 )
     903             :                 {
     904           0 :                     ZipEntry aEntry;
     905           0 :                     MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 26 ) );
     906             : 
     907           0 :                     aMemGrabber >> aEntry.nVersion;
     908           0 :                     if ( ( aEntry.nVersion & 1 ) != 1 )
     909             :                     {
     910           0 :                         aMemGrabber >> aEntry.nFlag;
     911           0 :                         aMemGrabber >> aEntry.nMethod;
     912             : 
     913           0 :                         if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED )
     914             :                         {
     915             :                             sal_uInt32 nCompressedSize, nSize;
     916             : 
     917           0 :                             aMemGrabber >> aEntry.nTime;
     918           0 :                             aMemGrabber >> aEntry.nCrc;
     919           0 :                             aMemGrabber >> nCompressedSize;
     920           0 :                             aMemGrabber >> nSize;
     921           0 :                             aMemGrabber >> aEntry.nPathLen;
     922           0 :                             aMemGrabber >> aEntry.nExtraLen;
     923             : 
     924             :                             // FIXME64: need to read the 64bit header instead
     925           0 :                             if ( nSize == 0xffffffff ||
     926           0 :                                  nCompressedSize == 0xffffffff ) {
     927           0 :                                 throw ZipException("PK64 zip file entry", uno::Reference < XInterface > () );
     928             :                             } else {
     929           0 :                                 aEntry.nCompressedSize = nCompressedSize;
     930           0 :                                 aEntry.nSize = nSize;
     931             :                             }
     932             : 
     933             :                             sal_Int32 nDescrLength =
     934           0 :                                 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 16 : 0;
     935             : 
     936           0 :                             sal_Int64 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize;
     937           0 :                             sal_Int64 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength;
     938           0 :                             if ( aEntry.nPathLen >= 0 && aEntry.nExtraLen >= 0
     939           0 :                                 && ( nGenPos + nPos + nBlockLength ) <= nLength )
     940             :                             {
     941             :                                 // read always in UTF8, some tools seem not to set UTF8 bit
     942           0 :                                 if( nPos + 30 + aEntry.nPathLen <= nBufSize )
     943           0 :                                     aEntry.sPath = OUString ( (sal_Char *) &pBuffer[nPos + 30],
     944             :                                                               aEntry.nPathLen,
     945           0 :                                                               RTL_TEXTENCODING_UTF8 );
     946             :                                 else
     947             :                                 {
     948           0 :                                     Sequence < sal_Int8 > aFileName;
     949           0 :                                     aGrabber.seek( nGenPos + nPos + 30 );
     950           0 :                                     aGrabber.readBytes( aFileName, aEntry.nPathLen );
     951           0 :                                     aEntry.sPath = OUString ( (sal_Char *) aFileName.getArray(),
     952             :                                                               aFileName.getLength(),
     953           0 :                                                               RTL_TEXTENCODING_UTF8 );
     954           0 :                                     aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength());
     955             :                                 }
     956             : 
     957           0 :                                 aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen;
     958             : 
     959           0 :                                 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) )
     960             :                                 {
     961           0 :                                     aEntry.nCrc = 0;
     962           0 :                                     aEntry.nCompressedSize = 0;
     963           0 :                                     aEntry.nSize = 0;
     964             :                                 }
     965             : 
     966           0 :                                 if ( aEntries.find( aEntry.sPath ) == aEntries.end() )
     967           0 :                                     aEntries[aEntry.sPath] = aEntry;
     968             :                             }
     969             :                         }
     970             :                     }
     971             : 
     972           0 :                     nPos += 4;
     973             :                 }
     974           0 :                 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 )
     975             :                 {
     976             :                     sal_Int32 nCRC32;
     977             :                     sal_uInt32 nCompressedSize32, nSize32;
     978             :                     sal_Int64 nCompressedSize, nSize;
     979           0 :                     MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 12 ) );
     980           0 :                     aMemGrabber >> nCRC32;
     981           0 :                     aMemGrabber >> nCompressedSize32;
     982           0 :                     aMemGrabber >> nSize32;
     983             : 
     984             :                     // FIXME64: work to be done here ...
     985           0 :                     nCompressedSize = nCompressedSize32;
     986           0 :                     nSize = nSize32;
     987             : 
     988           0 :                     for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); ++aIter )
     989             :                     {
     990           0 :                         ZipEntry aTmp = (*aIter).second;
     991             : 
     992             :                         // this is a broken package, accept this block not only for DEFLATED streams
     993           0 :                         if( (*aIter).second.nFlag & 8 )
     994             :                         {
     995           0 :                             sal_Int64 nStreamOffset = nGenPos + nPos - nCompressedSize;
     996           0 :                             if ( nStreamOffset == (*aIter).second.nOffset && nCompressedSize > (*aIter).second.nCompressedSize )
     997             :                             {
     998             :                                 // only DEFLATED blocks need to be checked
     999           0 :                                 sal_Bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize );
    1000             : 
    1001           0 :                                 if ( !bAcceptBlock )
    1002             :                                 {
    1003           0 :                                     sal_Int64 nRealSize = 0;
    1004           0 :                                     sal_Int32 nRealCRC = 0;
    1005           0 :                                     getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC );
    1006           0 :                                     bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 );
    1007             :                                 }
    1008             : 
    1009           0 :                                 if ( bAcceptBlock )
    1010             :                                 {
    1011           0 :                                     (*aIter).second.nCrc = nCRC32;
    1012           0 :                                     (*aIter).second.nCompressedSize = nCompressedSize;
    1013           0 :                                     (*aIter).second.nSize = nSize;
    1014             :                                 }
    1015             :                             }
    1016             : #if 0
    1017             : // for now ignore clearly broken streams
    1018             :                             else if( !(*aIter).second.nCompressedSize )
    1019             :                             {
    1020             :                                 (*aIter).second.nCrc = nCRC32;
    1021             :                                 sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nOffset;
    1022             :                                 (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nOffset;
    1023             :                                 (*aIter).second.nSize = nSize;
    1024             :                             }
    1025             : #endif
    1026             :                         }
    1027           0 :                     }
    1028             : 
    1029           0 :                     nPos += 4;
    1030             :                 }
    1031             :                 else
    1032           0 :                     nPos++;
    1033             :             }
    1034             : 
    1035           0 :             nGenPos += nPos;
    1036           0 :             aGrabber.seek( nGenPos );
    1037             :         }
    1038             : 
    1039           0 :         return 0;
    1040             :     }
    1041           0 :     catch ( IllegalArgumentException& )
    1042             :     {
    1043           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1044             :     }
    1045           0 :     catch ( NotConnectedException& )
    1046             :     {
    1047           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1048             :     }
    1049           0 :     catch ( BufferSizeExceededException& )
    1050             :     {
    1051           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1052           0 :     }
    1053             : }
    1054             : 
    1055           0 : sal_Bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry )
    1056             : {
    1057           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1058             : 
    1059           0 :     sal_Int32 nCRC = 0;
    1060           0 :     sal_Int64 nSize = 0;
    1061             : 
    1062           0 :     if( aEntry.nMethod == STORED )
    1063           0 :         return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc );
    1064             : 
    1065           0 :     getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC );
    1066           0 :     return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC );
    1067             : }
    1068             : 
    1069           0 : sal_Int32 ZipFile::getCRC( sal_Int64 nOffset, sal_Int64 nSize )
    1070             : {
    1071           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1072             : 
    1073           0 :     Sequence < sal_Int8 > aBuffer;
    1074           0 :     CRC32 aCRC;
    1075           0 :     sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nSize, static_cast< sal_Int64 >( 32000 ) ) );
    1076             : 
    1077           0 :     aGrabber.seek( nOffset );
    1078           0 :     for ( int ind = 0;
    1079           0 :           aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize;
    1080             :           ind++ )
    1081             :     {
    1082             :         sal_Int64 nLen = ::std::min( static_cast< sal_Int64 >( nBlockSize ),
    1083           0 :                                      nSize - ind * nBlockSize );
    1084           0 :         aCRC.updateSegment( aBuffer, 0, static_cast< sal_Int32 >( nLen ) );
    1085             :     }
    1086             : 
    1087           0 :     return aCRC.getValue();
    1088             : }
    1089             : 
    1090           0 : void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_Int64 *nSize, sal_Int32 *nCRC )
    1091             : {
    1092           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1093             : 
    1094           0 :     Sequence < sal_Int8 > aBuffer;
    1095           0 :     CRC32 aCRC;
    1096           0 :     sal_Int64 nRealSize = 0;
    1097           0 :     Inflater aInflaterLocal( sal_True );
    1098           0 :     sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nCompressedSize, static_cast< sal_Int64 >( 32000 ) ) );
    1099             : 
    1100           0 :     aGrabber.seek( nOffset );
    1101           0 :     for ( int ind = 0;
    1102           0 :           !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize;
    1103             :           ind++ )
    1104             :     {
    1105           0 :         Sequence < sal_Int8 > aData( nBlockSize );
    1106           0 :         sal_Int32 nLastInflated = 0;
    1107           0 :         sal_Int64 nInBlock = 0;
    1108             : 
    1109           0 :         aInflaterLocal.setInput( aBuffer );
    1110           0 :         do
    1111             :         {
    1112           0 :             nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize );
    1113           0 :             aCRC.updateSegment( aData, 0, nLastInflated );
    1114           0 :             nInBlock += nLastInflated;
    1115           0 :         } while( !aInflater.finished() && nLastInflated );
    1116             : 
    1117           0 :         nRealSize += nInBlock;
    1118           0 :     }
    1119             : 
    1120           0 :     *nSize = nRealSize;
    1121           0 :     *nCRC = aCRC.getValue();
    1122           0 : }
    1123             : 
    1124             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10