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

Generated by: LCOV version 1.10