LCOV - code coverage report
Current view: top level - package/source/zipapi - ZipFile.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 220 533 41.3 %
Date: 2014-04-11 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             : #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         722 : ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XComponentContext > & rxContext, sal_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         736 : , bRecoveryMode( sal_False )
      76             : {
      77         722 :     if (bInitialise)
      78             :     {
      79         267 :         if ( readCEN() == -1 )
      80             :         {
      81           1 :             aEntries.clear();
      82           1 :             throw ZipException( "stream data looks to be broken", uno::Reference < XInterface > () );
      83             :         }
      84             :     }
      85         708 : }
      86             : 
      87        5466 : ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XComponentContext > & rxContext, sal_Bool bInitialise, sal_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        5466 : , bRecoveryMode( bForceRecovery )
      96             : {
      97        5466 :     if (bInitialise)
      98             :     {
      99        5466 :         if ( bForceRecovery )
     100             :         {
     101           0 :             recover();
     102             :         }
     103        5466 :         else if ( readCEN() == -1 )
     104             :         {
     105           0 :             aEntries.clear();
     106           0 :             throw ZipException("stream data looks to be broken", uno::Reference < XInterface > () );
     107             :         }
     108             :     }
     109        5466 : }
     110             : 
     111       12318 : ZipFile::~ZipFile()
     112             : {
     113        6159 :     aEntries.clear();
     114        6159 : }
     115             : 
     116          27 : void ZipFile::setInputStream ( uno::Reference < XInputStream > xNewStream )
     117             : {
     118          27 :     ::osl::MutexGuard aGuard( m_aMutex );
     119             : 
     120          27 :     xStream = xNewStream;
     121          27 :     xSeek = uno::Reference < XSeekable > ( xStream, UNO_QUERY );
     122          27 :     aGrabber.setInputStream ( xStream );
     123          27 : }
     124             : 
     125          26 : uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData )
     126             : {
     127          26 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext;
     128          26 :     if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA256_1K )
     129             :     {
     130          22 :         uno::Reference< uno::XComponentContext > xContext = xArgContext;
     131          22 :         if ( !xContext.is() )
     132           0 :             xContext = comphelper::getProcessComponentContext();
     133             : 
     134          44 :         uno::Reference< xml::crypto::XNSSInitializer > xDigestContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     135             : 
     136          44 :         xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW );
     137             :     }
     138           4 :     else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K )
     139           4 :         xDigestContext.set( SHA1DigestContext::Create(), uno::UNO_SET_THROW );
     140             : 
     141          26 :     return xDigestContext;
     142             : }
     143             : 
     144          43 : uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt )
     145             : {
     146          43 :     uno::Reference< xml::crypto::XCipherContext > xResult;
     147             : 
     148             :     try
     149             :     {
     150          43 :         if (xEncryptionData->m_nDerivedKeySize < 0)
     151             :         {
     152             :             throw ZipIOException("Invalid derived key length!",
     153           0 :                                   uno::Reference< XInterface >() );
     154             :         }
     155             : 
     156          43 :         uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize );
     157          86 :         if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ),
     158          43 :                             aDerivedKey.getLength(),
     159          43 :                             reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ),
     160          43 :                             xEncryptionData->m_aKey.getLength(),
     161          43 :                             reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ),
     162          43 :                             xEncryptionData->m_aSalt.getLength(),
     163         215 :                             xEncryptionData->m_nIterationCount ) )
     164             :         {
     165             :             throw ZipIOException("Can not create derived key!",
     166           0 :                                   uno::Reference< XInterface >() );
     167             :         }
     168             : 
     169          43 :         if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
     170             :         {
     171          35 :             uno::Reference< uno::XComponentContext > xContext = xArgContext;
     172          35 :             if ( !xContext.is() )
     173           0 :                 xContext = comphelper::getProcessComponentContext();
     174             : 
     175          70 :             uno::Reference< xml::crypto::XNSSInitializer > xCipherContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     176             : 
     177          70 :             xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() );
     178             :         }
     179           8 :         else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 )
     180             :         {
     181           8 :             xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt );
     182             :         }
     183             :         else
     184             :         {
     185             :             throw ZipIOException("Unknown cipher algorithm is requested!",
     186           0 :                                   uno::Reference< XInterface >() );
     187          43 :         }
     188             :     }
     189           0 :     catch( ... )
     190             :     {
     191             :         OSL_ENSURE( false, "Can not create cipher context!" );
     192             :     }
     193             : 
     194          43 :     return xResult;
     195             : }
     196             : 
     197           0 : void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData,
     198             :                                 sal_Int64 nSize,
     199             :                                 const OUString& aMediaType,
     200             :                                 sal_Int8 * & pHeader )
     201             : {
     202             :     // I think it's safe to restrict vector and salt length to 2 bytes !
     203           0 :     sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() );
     204           0 :     sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() );
     205           0 :     sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() );
     206           0 :     sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) );
     207             : 
     208             :     // First the header
     209           0 :     *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF;
     210           0 :     *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF;
     211           0 :     *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF;
     212           0 :     *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF;
     213             : 
     214             :     // Then the version
     215           0 :     *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF;
     216           0 :     *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF;
     217             : 
     218             :     // Then the iteration Count
     219           0 :     sal_Int32 nIterationCount = rData->m_nIterationCount;
     220           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF);
     221           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF);
     222           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF);
     223           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF);
     224             : 
     225             :     // FIXME64: need to handle larger sizes
     226             :     // Then the size:
     227           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF);
     228           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF);
     229           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF);
     230           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF);
     231             : 
     232             :     // Then the encryption algorithm
     233           0 :     sal_Int32 nEncAlgID = rData->m_nEncAlg;
     234           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF);
     235           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF);
     236           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF);
     237           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF);
     238             : 
     239             :     // Then the checksum algorithm
     240           0 :     sal_Int32 nChecksumAlgID = rData->m_nCheckAlg;
     241           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF);
     242           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF);
     243           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF);
     244           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF);
     245             : 
     246             :     // Then the derived key size
     247           0 :     sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize;
     248           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF);
     249           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF);
     250           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF);
     251           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF);
     252             : 
     253             :     // Then the start key generation algorithm
     254           0 :     sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID;
     255           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF);
     256           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF);
     257           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF);
     258           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF);
     259             : 
     260             :     // Then the salt length
     261           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF);
     262           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF);
     263             : 
     264             :     // Then the IV length
     265           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF);
     266           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF);
     267             : 
     268             :     // Then the digest length
     269           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF);
     270           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF);
     271             : 
     272             :     // Then the mediatype length
     273           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF);
     274           0 :     *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF);
     275             : 
     276             :     // Then the salt content
     277           0 :     memcpy ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength );
     278           0 :     pHeader += nSaltLength;
     279             : 
     280             :     // Then the IV content
     281           0 :     memcpy ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength );
     282           0 :     pHeader += nIVLength;
     283             : 
     284             :     // Then the digest content
     285           0 :     memcpy ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength );
     286           0 :     pHeader += nDigestLength;
     287             : 
     288             :     // Then the mediatype itself
     289           0 :     memcpy ( pHeader, aMediaType.getStr(), nMediaTypeLength );
     290           0 :     pHeader += nMediaTypeLength;
     291           0 : }
     292             : 
     293           0 : sal_Bool ZipFile::StaticFillData (  ::rtl::Reference< BaseEncryptionData > & rData,
     294             :                                     sal_Int32 &rEncAlg,
     295             :                                     sal_Int32 &rChecksumAlg,
     296             :                                     sal_Int32 &rDerivedKeySize,
     297             :                                     sal_Int32 &rStartKeyGenID,
     298             :                                     sal_Int32 &rSize,
     299             :                                     OUString& aMediaType,
     300             :                                     const uno::Reference< XInputStream >& rStream )
     301             : {
     302           0 :     sal_Bool bOk = sal_False;
     303           0 :     const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4;
     304           0 :     Sequence < sal_Int8 > aBuffer ( nHeaderSize );
     305           0 :     if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) )
     306             :     {
     307           0 :         sal_Int16 nPos = 0;
     308           0 :         sal_Int8 *pBuffer = aBuffer.getArray();
     309           0 :         sal_Int16 nVersion = pBuffer[nPos++] & 0xFF;
     310           0 :         nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8;
     311           0 :         if ( nVersion == n_ConstCurrentVersion )
     312             :         {
     313           0 :             sal_Int32 nCount = pBuffer[nPos++] & 0xFF;
     314           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 8;
     315           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 16;
     316           0 :             nCount |= ( pBuffer[nPos++] & 0xFF ) << 24;
     317           0 :             rData->m_nIterationCount = nCount;
     318             : 
     319           0 :             rSize  =   pBuffer[nPos++] & 0xFF;
     320           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 8;
     321           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 16;
     322           0 :             rSize |= ( pBuffer[nPos++] & 0xFF ) << 24;
     323             : 
     324           0 :             rEncAlg   =   pBuffer[nPos++] & 0xFF;
     325           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     326           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     327           0 :             rEncAlg  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     328             : 
     329           0 :             rChecksumAlg   =   pBuffer[nPos++] & 0xFF;
     330           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     331           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     332           0 :             rChecksumAlg  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     333             : 
     334           0 :             rDerivedKeySize   =   pBuffer[nPos++] & 0xFF;
     335           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     336           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     337           0 :             rDerivedKeySize  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     338             : 
     339           0 :             rStartKeyGenID   =   pBuffer[nPos++] & 0xFF;
     340           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 8;
     341           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 16;
     342           0 :             rStartKeyGenID  |= ( pBuffer[nPos++] & 0xFF ) << 24;
     343             : 
     344           0 :             sal_Int16 nSaltLength =   pBuffer[nPos++] & 0xFF;
     345           0 :             nSaltLength          |= ( pBuffer[nPos++] & 0xFF ) << 8;
     346           0 :             sal_Int16 nIVLength   = ( pBuffer[nPos++] & 0xFF );
     347           0 :             nIVLength            |= ( pBuffer[nPos++] & 0xFF ) << 8;
     348           0 :             sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF;
     349           0 :             nDigestLength        |= ( pBuffer[nPos++] & 0xFF ) << 8;
     350             : 
     351           0 :             sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF;
     352           0 :             nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
     353             : 
     354           0 :             if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) )
     355             :             {
     356           0 :                 rData->m_aSalt.realloc ( nSaltLength );
     357           0 :                 memcpy ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength );
     358           0 :                 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) )
     359             :                 {
     360           0 :                     rData->m_aInitVector.realloc ( nIVLength );
     361           0 :                     memcpy ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength );
     362           0 :                     if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) )
     363             :                     {
     364           0 :                         rData->m_aDigest.realloc ( nDigestLength );
     365           0 :                         memcpy ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength );
     366             : 
     367           0 :                         if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) )
     368             :                         {
     369           0 :                             aMediaType = OUString( (sal_Unicode*)aBuffer.getConstArray(),
     370           0 :                                                             nMediaTypeLength / sizeof( sal_Unicode ) );
     371           0 :                             bOk = sal_True;
     372             :                         }
     373             :                     }
     374             :                 }
     375             :             }
     376             :         }
     377             :     }
     378           0 :     return bOk;
     379             : }
     380             : 
     381           0 : uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const uno::Reference< uno::XComponentContext >& rxContext,
     382             :                                                                 const uno::Reference< XInputStream >& xStream,
     383             :                                                                 const ::rtl::Reference< EncryptionData > &rData )
     384             :         throw ( packages::WrongPasswordException, ZipIOException, RuntimeException )
     385             : {
     386           0 :     if ( !rData.is() )
     387             :         throw ZipIOException("Encrypted stream without encryption data!\n",
     388           0 :                             uno::Reference< XInterface >() );
     389             : 
     390           0 :     if ( !rData->m_aKey.getLength() )
     391           0 :         throw packages::WrongPasswordException(THROW_WHERE, uno::Reference< uno::XInterface >() );
     392             : 
     393           0 :     uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY );
     394           0 :     if ( !xSeek.is() )
     395             :         throw ZipIOException("The stream must be seekable!\n",
     396           0 :                             uno::Reference< XInterface >() );
     397             : 
     398             :     // if we have a digest, then this file is an encrypted one and we should
     399             :     // check if we can decrypt it or not
     400             :     OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     401           0 :     if ( rData->m_aDigest.getLength() )
     402             :     {
     403           0 :         sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() );
     404           0 :         if ( nSize > n_ConstDigestLength + 32 )
     405           0 :             nSize = n_ConstDigestLength + 32;
     406             : 
     407             :         // skip header
     408           0 :         xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() +
     409           0 :                                 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() );
     410             : 
     411             :         // Only want to read enough to verify the digest
     412           0 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     413             : 
     414           0 :         xStream->readBytes( aReadBuffer, nSize );
     415             : 
     416           0 :         if ( !StaticHasValidPassword( rxContext, aReadBuffer, rData ) )
     417           0 :             throw packages::WrongPasswordException(THROW_WHERE, uno::Reference< uno::XInterface >() );
     418             :     }
     419             : 
     420           0 :     return new XUnbufferedStream( rxContext, xStream, rData );
     421             : }
     422             : 
     423             : #if 0
     424             : // for debugging purposes
     425             : void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence )
     426             : {
     427             :     if ( aSequence.getLength() )
     428             :     {
     429             :         sal_Int32* pPointer = *( (sal_Int32**)&aSequence );
     430             :         sal_Int32 nSize = *( pPointer + 1 );
     431             :         sal_Int32 nMemSize = *( pPointer - 2 );
     432             :         sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) );
     433             :         OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" );
     434             :     }
     435             : }
     436             : #endif
     437             : 
     438          21 : sal_Bool ZipFile::StaticHasValidPassword( const uno::Reference< uno::XComponentContext >& rxContext, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData )
     439             : {
     440          21 :     if ( !rData.is() || !rData->m_aKey.getLength() )
     441           0 :         return sal_False;
     442             : 
     443          21 :     sal_Bool bRet = sal_False;
     444             : 
     445          21 :     uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( rxContext, rData, false ), uno::UNO_SET_THROW );
     446             : 
     447          42 :     uno::Sequence< sal_Int8 > aDecryptBuffer;
     448          42 :     uno::Sequence< sal_Int8 > aDecryptBuffer2;
     449             :     try
     450             :     {
     451          21 :         aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer );
     452          21 :         aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose();
     453             :     }
     454          13 :     catch( uno::Exception& )
     455             :     {
     456             :         // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream
     457             :         // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks )
     458             :     }
     459             : 
     460          21 :     if ( aDecryptBuffer2.getLength() )
     461             :     {
     462           4 :         sal_Int32 nOldLen = aDecryptBuffer.getLength();
     463           4 :         aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() );
     464           4 :         memcpy( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() );
     465             :     }
     466             : 
     467          21 :     if ( aDecryptBuffer.getLength() > n_ConstDigestLength )
     468          12 :         aDecryptBuffer.realloc( n_ConstDigestLength );
     469             : 
     470          42 :     uno::Sequence< sal_Int8 > aDigestSeq;
     471          42 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( rxContext, rData ), uno::UNO_SET_THROW );
     472             : 
     473          21 :     xDigestContext->updateDigest( aDecryptBuffer );
     474          21 :     aDigestSeq = xDigestContext->finalizeDigestAndDispose();
     475             : 
     476             :     // If we don't have a digest, then we have to assume that the password is correct
     477          46 :     if (  rData->m_aDigest.getLength() != 0  &&
     478          42 :           ( aDigestSeq.getLength() != rData->m_aDigest.getLength() ||
     479          21 :             0 != memcmp ( aDigestSeq.getConstArray(),
     480          21 :                                      rData->m_aDigest.getConstArray(),
     481          42 :                                     aDigestSeq.getLength() ) ) )
     482             :     {
     483             :         // We should probably tell the user that the password they entered was wrong
     484             :     }
     485             :     else
     486          17 :         bRet = sal_True;
     487             : 
     488          42 :     return bRet;
     489             : }
     490             : 
     491          21 : sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< EncryptionData >& rData )
     492             : {
     493          21 :     ::osl::MutexGuard aGuard( m_aMutex );
     494             : 
     495          21 :     sal_Bool bRet = sal_False;
     496          21 :     if ( rData.is() && rData->m_aKey.getLength() )
     497             :     {
     498          21 :         xSeek->seek( rEntry.nOffset );
     499          21 :         sal_Int64 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize;
     500             : 
     501             :         // Only want to read enough to verify the digest
     502          21 :         if ( nSize > n_ConstDigestDecrypt )
     503          11 :             nSize = n_ConstDigestDecrypt;
     504             : 
     505          21 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     506             : 
     507          21 :         xStream->readBytes( aReadBuffer, nSize );
     508             : 
     509          21 :         bRet = StaticHasValidPassword( m_xContext, aReadBuffer, rData );
     510             :     }
     511             : 
     512          21 :     return bRet;
     513             : }
     514             : 
     515       37053 : uno::Reference< XInputStream > ZipFile::createUnbufferedStream(
     516             :             SotMutexHolderRef aMutexHolder,
     517             :             ZipEntry & rEntry,
     518             :             const ::rtl::Reference< EncryptionData > &rData,
     519             :             sal_Int8 nStreamMode,
     520             :             sal_Bool bIsEncrypted,
     521             :             const OUString& aMediaType )
     522             : {
     523       37053 :     ::osl::MutexGuard aGuard( m_aMutex );
     524             : 
     525       37053 :     return new XUnbufferedStream ( m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode );
     526             : }
     527             : 
     528        5466 : ZipEnumeration * SAL_CALL ZipFile::entries(  )
     529             : {
     530        5466 :     return new ZipEnumeration ( aEntries );
     531             : }
     532             : 
     533        2900 : uno::Reference< XInputStream > SAL_CALL ZipFile::getInputStream( ZipEntry& rEntry,
     534             :         const ::rtl::Reference< EncryptionData > &rData,
     535             :         sal_Bool bIsEncrypted,
     536             :         SotMutexHolderRef aMutexHolder )
     537             :     throw(IOException, ZipException, RuntimeException)
     538             : {
     539        2900 :     ::osl::MutexGuard aGuard( m_aMutex );
     540             : 
     541        2900 :     if ( rEntry.nOffset <= 0 )
     542        2900 :         readLOC( rEntry );
     543             : 
     544             :     // We want to return a rawStream if we either don't have a key or if the
     545             :     // key is wrong
     546             : 
     547        2900 :     sal_Bool bNeedRawStream = rEntry.nMethod == STORED;
     548             : 
     549             :     // if we have a digest, then this file is an encrypted one and we should
     550             :     // check if we can decrypt it or not
     551        2900 :     if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() )
     552           0 :         bNeedRawStream = !hasValidPassword ( rEntry, rData );
     553             : 
     554             :     return createUnbufferedStream ( aMutexHolder,
     555             :                                     rEntry,
     556             :                                     rData,
     557             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     558        2900 :                                     bIsEncrypted );
     559             : }
     560             : 
     561       34021 : uno::Reference< XInputStream > SAL_CALL ZipFile::getDataStream( ZipEntry& rEntry,
     562             :         const ::rtl::Reference< EncryptionData > &rData,
     563             :         sal_Bool bIsEncrypted,
     564             :         SotMutexHolderRef aMutexHolder )
     565             :     throw ( packages::WrongPasswordException,
     566             :             IOException,
     567             :             ZipException,
     568             :             RuntimeException )
     569             : {
     570       34021 :     ::osl::MutexGuard aGuard( m_aMutex );
     571             : 
     572       34021 :     if ( rEntry.nOffset <= 0 )
     573       24875 :         readLOC( rEntry );
     574             : 
     575             :     // An exception must be thrown in case stream is encrypted and
     576             :     // there is no key or the key is wrong
     577       34021 :     sal_Bool bNeedRawStream = sal_False;
     578       34021 :     if ( bIsEncrypted )
     579             :     {
     580             :         // in case no digest is provided there is no way
     581             :         // to detect password correctness
     582          21 :         if ( !rData.is() )
     583             :             throw ZipException("Encrypted stream without encryption data!\n",
     584           0 :                                 uno::Reference< XInterface >() );
     585             : 
     586             :         // if we have a digest, then this file is an encrypted one and we should
     587             :         // check if we can decrypt it or not
     588             :         OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     589          21 :         if ( rData->m_aDigest.getLength() && !hasValidPassword ( rEntry, rData ) )
     590           4 :                 throw packages::WrongPasswordException(THROW_WHERE, uno::Reference< uno::XInterface >() );
     591             :     }
     592             :     else
     593       34000 :         bNeedRawStream = ( rEntry.nMethod == STORED );
     594             : 
     595             :     return createUnbufferedStream ( aMutexHolder,
     596             :                                     rEntry,
     597             :                                     rData,
     598             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     599       34017 :                                     bIsEncrypted );
     600             : }
     601             : 
     602         136 : uno::Reference< XInputStream > SAL_CALL ZipFile::getRawData( ZipEntry& rEntry,
     603             :         const ::rtl::Reference< EncryptionData >& rData,
     604             :         sal_Bool bIsEncrypted,
     605             :         SotMutexHolderRef aMutexHolder )
     606             :     throw(IOException, ZipException, RuntimeException)
     607             : {
     608         136 :     ::osl::MutexGuard aGuard( m_aMutex );
     609             : 
     610         136 :     if ( rEntry.nOffset <= 0 )
     611          68 :         readLOC( rEntry );
     612             : 
     613         136 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted );
     614             : }
     615             : 
     616           0 : uno::Reference< XInputStream > SAL_CALL ZipFile::getWrappedRawStream(
     617             :         ZipEntry& rEntry,
     618             :         const ::rtl::Reference< EncryptionData >& rData,
     619             :         const OUString& aMediaType,
     620             :         SotMutexHolderRef aMutexHolder )
     621             :     throw ( packages::NoEncryptionException,
     622             :             IOException,
     623             :             ZipException,
     624             :             RuntimeException )
     625             : {
     626           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     627             : 
     628           0 :     if ( !rData.is() )
     629           0 :         throw packages::NoEncryptionException(THROW_WHERE, uno::Reference< uno::XInterface >() );
     630             : 
     631           0 :     if ( rEntry.nOffset <= 0 )
     632           0 :         readLOC( rEntry );
     633             : 
     634           0 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType );
     635             : }
     636             : 
     637       27843 : sal_Bool ZipFile::readLOC( ZipEntry &rEntry )
     638             :     throw(IOException, ZipException, RuntimeException)
     639             : {
     640       27843 :     ::osl::MutexGuard aGuard( m_aMutex );
     641             : 
     642             :     sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize;
     643             :     sal_Int16 nVersion, nFlag, nHow, nPathLen, nExtraLen;
     644       27843 :     sal_Int64 nPos = -rEntry.nOffset;
     645             : 
     646       27843 :     aGrabber.seek(nPos);
     647       27843 :     aGrabber >> nTestSig;
     648             : 
     649       27843 :     if (nTestSig != LOCSIG)
     650           0 :         throw ZipIOException("Invalid LOC header (bad signature)", uno::Reference < XInterface > () );
     651       27843 :     aGrabber >> nVersion;
     652       27843 :     aGrabber >> nFlag;
     653       27843 :     aGrabber >> nHow;
     654       27843 :     aGrabber >> nTime;
     655       27843 :     aGrabber >> nCRC;
     656       27843 :     aGrabber >> nCompressedSize;
     657       27843 :     aGrabber >> nSize;
     658       27843 :     aGrabber >> nPathLen;
     659       27843 :     aGrabber >> nExtraLen;
     660       27843 :     rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
     661             : 
     662             :     // FIXME64: need to read 64bit LOC
     663             : 
     664       27843 :     sal_Bool bBroken = sal_False;
     665             : 
     666             :     try
     667             :     {
     668             :         // read always in UTF8, some tools seem not to set UTF8 bit
     669       27843 :         uno::Sequence < sal_Int8 > aNameBuffer( nPathLen );
     670       27843 :         sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen );
     671       27843 :         if ( nRead < aNameBuffer.getLength() )
     672           0 :                 aNameBuffer.realloc( nRead );
     673             : 
     674       27843 :         OUString sLOCPath = OUString::intern( (sal_Char *) aNameBuffer.getArray(),
     675             :                                                           aNameBuffer.getLength(),
     676       83529 :                                                           RTL_TEXTENCODING_UTF8 );
     677             : 
     678       27843 :         if ( rEntry.nPathLen == -1 ) // the file was created
     679             :         {
     680           0 :             rEntry.nPathLen = nPathLen;
     681           0 :             rEntry.sPath = sLOCPath;
     682             :         }
     683             : 
     684             :         // check basic local file header / entry consistency, just
     685             :         // plain ignore bits 1 & 2 of the flag field - they are either
     686             :         // purely informative, or even fully undefined (depending on
     687             :         // nMethod)
     688             :         // Do *not* compare nMethod / nHow, older versions with
     689             :         // encrypted streams write mismatching DEFLATE/STORE pairs
     690             :         // there.
     691             :         // Do *not* compare timestamps, since MSO 2010 can produce documents
     692             :         // with timestamp difference in the central directory entry and local
     693             :         // file header.
     694       27843 :         bBroken = rEntry.nVersion != nVersion
     695       27843 :                         || rEntry.nPathLen != nPathLen
     696       83529 :                         || !rEntry.sPath.equals( sLOCPath );
     697             :     }
     698           0 :     catch(...)
     699             :     {
     700           0 :         bBroken = sal_True;
     701             :     }
     702             : 
     703       27843 :     if ( bBroken && !bRecoveryMode )
     704             :         throw ZipIOException("The stream seems to be broken!",
     705           0 :                             uno::Reference< XInterface >() );
     706             : 
     707       27843 :     return sal_True;
     708             : }
     709             : 
     710        5733 : sal_Int32 ZipFile::findEND( )
     711             :     throw(IOException, ZipException, RuntimeException)
     712             : {
     713             :     // this method is called in constructor only, no need for mutex
     714             :     sal_Int32 nLength, nPos, nEnd;
     715        5733 :     Sequence < sal_Int8 > aBuffer;
     716             :     try
     717             :     {
     718        5733 :         nLength = static_cast <sal_Int32 > (aGrabber.getLength());
     719        5733 :         if (nLength == 0 || nLength < ENDHDR)
     720           1 :             return -1;
     721        5732 :         nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
     722        5732 :         nEnd = nPos >= 0 ? nPos : 0 ;
     723             : 
     724        5732 :         aGrabber.seek( nEnd );
     725        5732 :         aGrabber.readBytes ( aBuffer, nLength - nEnd );
     726             : 
     727        5732 :         const sal_Int8 *pBuffer = aBuffer.getConstArray();
     728             : 
     729        5732 :         nPos = nLength - nEnd - ENDHDR;
     730       15577 :         while ( nPos >= 0 )
     731             :         {
     732        9832 :             if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
     733        5719 :                 return nPos + nEnd;
     734        4113 :             nPos--;
     735             :         }
     736             :     }
     737           0 :     catch ( IllegalArgumentException& )
     738             :     {
     739           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     740             :     }
     741           0 :     catch ( NotConnectedException& )
     742             :     {
     743           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     744             :     }
     745           0 :     catch ( BufferSizeExceededException& )
     746             :     {
     747           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     748             :     }
     749          13 :     throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     750             : }
     751             : 
     752        5733 : sal_Int32 ZipFile::readCEN()
     753             :     throw(IOException, ZipException, RuntimeException)
     754             : {
     755             :     // this method is called in constructor only, no need for mutex
     756        5733 :     sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos;
     757             :     sal_uInt16 nCount, nTotal;
     758             : 
     759             :     try
     760             :     {
     761        5733 :         nEndPos = findEND();
     762        5720 :         if (nEndPos == -1)
     763           1 :             return -1;
     764        5719 :         aGrabber.seek(nEndPos + ENDTOT);
     765        5719 :         aGrabber >> nTotal;
     766        5719 :         aGrabber >> nCenLen;
     767        5719 :         aGrabber >> nCenOff;
     768             : 
     769        5719 :         if ( nTotal * CENHDR > nCenLen )
     770           0 :             throw ZipException("invalid END header (bad entry count)", uno::Reference < XInterface > () );
     771             : 
     772        5719 :         if ( nTotal > ZIP_MAXENTRIES )
     773           0 :             throw ZipException("too many entries in ZIP File", uno::Reference < XInterface > () );
     774             : 
     775        5719 :         if ( nCenLen < 0 || nCenLen > nEndPos )
     776           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     777             : 
     778        5719 :         nCenPos = nEndPos - nCenLen;
     779             : 
     780        5719 :         if ( nCenOff < 0 || nCenOff > nCenPos )
     781           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     782             : 
     783        5719 :         nLocPos = nCenPos - nCenOff;
     784        5719 :         aGrabber.seek( nCenPos );
     785        5719 :         Sequence < sal_Int8 > aCENBuffer ( nCenLen );
     786        5719 :         sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
     787        5719 :         if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
     788           0 :             throw ZipException ("Error reading CEN into memory buffer!", uno::Reference < XInterface > () );
     789             : 
     790       11438 :         MemoryByteGrabber aMemGrabber ( aCENBuffer );
     791             : 
     792       11438 :         ZipEntry aEntry;
     793             :         sal_Int32 nTestSig;
     794             :         sal_Int16 nCommentLen;
     795             : 
     796      359659 :         for (nCount = 0 ; nCount < nTotal; nCount++)
     797             :         {
     798      353940 :             aMemGrabber >> nTestSig;
     799      353940 :             if ( nTestSig != CENSIG )
     800           0 :                 throw ZipException("Invalid CEN header (bad signature)", uno::Reference < XInterface > () );
     801             : 
     802      353940 :             aMemGrabber.skipBytes ( 2 );
     803      353940 :             aMemGrabber >> aEntry.nVersion;
     804             : 
     805      353940 :             if ( ( aEntry.nVersion & 1 ) == 1 )
     806           0 :                 throw ZipException("Invalid CEN header (encrypted entry)", uno::Reference < XInterface > () );
     807             : 
     808      353940 :             aMemGrabber >> aEntry.nFlag;
     809      353940 :             aMemGrabber >> aEntry.nMethod;
     810             : 
     811      353940 :             if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED)
     812           0 :                 throw ZipException("Invalid CEN header (bad compression method)", uno::Reference < XInterface > () );
     813             : 
     814      353940 :             aMemGrabber >> aEntry.nTime;
     815      353940 :             aMemGrabber >> aEntry.nCrc;
     816             : 
     817             :             sal_uInt32 nCompressedSize, nSize, nOffset;
     818             : 
     819      353940 :             aMemGrabber >> nCompressedSize;
     820      353940 :             aMemGrabber >> nSize;
     821      353940 :             aMemGrabber >> aEntry.nPathLen;
     822      353940 :             aMemGrabber >> aEntry.nExtraLen;
     823      353940 :             aMemGrabber >> nCommentLen;
     824      353940 :             aMemGrabber.skipBytes ( 8 );
     825      353940 :             aMemGrabber >> nOffset;
     826             : 
     827             :             // FIXME64: need to read the 64bit header instead
     828      707880 :             if ( nSize == 0xffffffff ||
     829      707880 :                  nOffset == 0xffffffff ||
     830      353940 :                  nCompressedSize == 0xffffffff ) {
     831           0 :                 throw ZipException("PK64 zip file entry", uno::Reference < XInterface > () );
     832             :             } else {
     833      353940 :                 aEntry.nCompressedSize = nCompressedSize;
     834      353940 :                 aEntry.nSize = nSize;
     835      353940 :                 aEntry.nOffset = nOffset;
     836             :             }
     837             : 
     838      353940 :             aEntry.nOffset += nLocPos;
     839      353940 :             aEntry.nOffset *= -1;
     840             : 
     841      353940 :             if ( aEntry.nPathLen < 0 )
     842           0 :                 throw ZipException("unexpected name length", uno::Reference < XInterface > () );
     843             : 
     844      353940 :             if ( nCommentLen < 0 )
     845           0 :                 throw ZipException("unexpected comment length", uno::Reference < XInterface > () );
     846             : 
     847      353940 :             if ( aEntry.nExtraLen < 0 )
     848           0 :                 throw ZipException("unexpected extra header info length", uno::Reference < XInterface > () );
     849             : 
     850             :             // read always in UTF8, some tools seem not to set UTF8 bit
     851      707880 :             aEntry.sPath = OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(),
     852             :                                                    aEntry.nPathLen,
     853      353940 :                                                    RTL_TEXTENCODING_UTF8 );
     854             : 
     855      353940 :             if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, true ) )
     856           0 :                 throw ZipException("Zip entry has an invalid name.", uno::Reference < XInterface > () );
     857             : 
     858      353940 :             aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen );
     859      353940 :             aEntries[aEntry.sPath] = aEntry;
     860             :         }
     861             : 
     862        5719 :         if (nCount != nTotal)
     863        5719 :             throw ZipException("Count != Total", uno::Reference < XInterface > () );
     864             :     }
     865           0 :     catch ( IllegalArgumentException & )
     866             :     {
     867             :         // seek can throw this...
     868           0 :         nCenPos = -1; // make sure we return -1 to indicate an error
     869             :     }
     870        5719 :     return nCenPos;
     871             : }
     872             : 
     873           0 : sal_Int32 ZipFile::recover()
     874             :     throw(IOException, ZipException, RuntimeException)
     875             : {
     876           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     877             : 
     878             :     sal_Int64 nLength;
     879           0 :     Sequence < sal_Int8 > aBuffer;
     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_Int64 nBlockSize = ::std::min(nSize, static_cast< sal_Int64 >(32000));
    1076             : 
    1077           0 :     aGrabber.seek( nOffset );
    1078           0 :     for (sal_Int64 ind = 0;
    1079           0 :          aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize;
    1080             :          ++ind)
    1081             :     {
    1082           0 :         sal_Int64 nLen = ::std::min(nBlockSize, nSize - ind * nBlockSize);
    1083           0 :         aCRC.updateSegment(aBuffer, 0, static_cast<sal_Int32>(nLen));
    1084             :     }
    1085             : 
    1086           0 :     return aCRC.getValue();
    1087             : }
    1088             : 
    1089           0 : void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_Int64 *nSize, sal_Int32 *nCRC )
    1090             : {
    1091           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1092             : 
    1093           0 :     Sequence < sal_Int8 > aBuffer;
    1094           0 :     CRC32 aCRC;
    1095           0 :     sal_Int64 nRealSize = 0;
    1096           0 :     Inflater aInflaterLocal( true );
    1097           0 :     sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nCompressedSize, static_cast< sal_Int64 >( 32000 ) ) );
    1098             : 
    1099           0 :     aGrabber.seek( nOffset );
    1100           0 :     for ( int ind = 0;
    1101           0 :           !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize;
    1102             :           ind++ )
    1103             :     {
    1104           0 :         Sequence < sal_Int8 > aData( nBlockSize );
    1105           0 :         sal_Int32 nLastInflated = 0;
    1106           0 :         sal_Int64 nInBlock = 0;
    1107             : 
    1108           0 :         aInflaterLocal.setInput( aBuffer );
    1109           0 :         do
    1110             :         {
    1111           0 :             nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize );
    1112           0 :             aCRC.updateSegment( aData, 0, nLastInflated );
    1113           0 :             nInBlock += nLastInflated;
    1114           0 :         } while( !aInflater.finished() && nLastInflated );
    1115             : 
    1116           0 :         nRealSize += nInBlock;
    1117           0 :     }
    1118             : 
    1119           0 :     *nSize = nRealSize;
    1120           0 :     *nCRC = aCRC.getValue();
    1121           0 : }
    1122             : 
    1123             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10