LCOV - code coverage report
Current view: top level - libreoffice/package/source/zipapi - ZipFile.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 193 527 36.6 %
Date: 2012-12-27 Functions: 14 24 58.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      22             : #include <com/sun/star/ucb/XProgressHandler.hpp>
      23             : #include <com/sun/star/packages/zip/ZipConstants.hpp>
      24             : #include <com/sun/star/xml/crypto/XCipherContext.hpp>
      25             : #include <com/sun/star/xml/crypto/XDigestContext.hpp>
      26             : #include <com/sun/star/xml/crypto/XCipherContextSupplier.hpp>
      27             : #include <com/sun/star/xml/crypto/XDigestContextSupplier.hpp>
      28             : #include <com/sun/star/xml/crypto/CipherID.hpp>
      29             : #include <com/sun/star/xml/crypto/DigestID.hpp>
      30             : #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
      31             : 
      32             : #include <comphelper/storagehelper.hxx>
      33             : #include <comphelper/processfactory.hxx>
      34             : #include <rtl/digest.h>
      35             : 
      36             : #include <vector>
      37             : 
      38             : #include "blowfishcontext.hxx"
      39             : #include "sha1context.hxx"
      40             : #include <ZipFile.hxx>
      41             : #include <ZipEnumeration.hxx>
      42             : #include <XUnbufferedStream.hxx>
      43             : #include <PackageConstants.hxx>
      44             : #include <EncryptedDataHeader.hxx>
      45             : #include <EncryptionData.hxx>
      46             : #include <MemoryByteGrabber.hxx>
      47             : 
      48             : #include <CRC32.hxx>
      49             : 
      50             : #define AES_CBC_BLOCK_SIZE 16
      51             : 
      52             : using namespace com::sun::star;
      53             : using namespace com::sun::star::io;
      54             : using namespace com::sun::star::uno;
      55             : using namespace com::sun::star::ucb;
      56             : using namespace com::sun::star::lang;
      57             : using namespace com::sun::star::packages;
      58             : using namespace com::sun::star::packages::zip;
      59             : using namespace com::sun::star::packages::zip::ZipConstants;
      60             : 
      61             : using rtl::OUString;
      62             : using ZipUtils::Inflater;
      63             : 
      64             : /** This class is used to read entries from a zip file
      65             :  */
      66          33 : ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference < XComponentContext > & rxContext, sal_Bool bInitialise )
      67             :     throw(IOException, ZipException, RuntimeException)
      68             : : aGrabber(xInput)
      69             : , aInflater (sal_True)
      70             : , xStream(xInput)
      71             : , xSeek(xInput, UNO_QUERY)
      72             : , m_xContext ( rxContext )
      73          33 : , bRecoveryMode( sal_False )
      74             : {
      75          33 :     if (bInitialise)
      76             :     {
      77           0 :         if ( readCEN() == -1 )
      78             :         {
      79           0 :             aEntries.clear();
      80           0 :             throw ZipException( "stream data looks to be broken", uno::Reference < XInterface > () );
      81             :         }
      82             :     }
      83          33 : }
      84             : 
      85             : 
      86             : 
      87         420 : 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 (sal_True)
      91             : , xStream(xInput)
      92             : , xSeek(xInput, UNO_QUERY)
      93             : , m_xContext ( rxContext )
      94             : , xProgressHandler( xProgress )
      95         420 : , bRecoveryMode( bForceRecovery )
      96             : {
      97         420 :     if (bInitialise)
      98             :     {
      99         420 :         if ( bForceRecovery )
     100             :         {
     101           0 :             recover();
     102             :         }
     103         420 :         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         420 : }
     110             : 
     111         886 : ZipFile::~ZipFile()
     112             : {
     113         443 :     aEntries.clear();
     114         443 : }
     115             : 
     116           0 : void ZipFile::setInputStream ( uno::Reference < XInputStream > xNewStream )
     117             : {
     118           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     119             : 
     120           0 :     xStream = xNewStream;
     121           0 :     xSeek = uno::Reference < XSeekable > ( xStream, UNO_QUERY );
     122           0 :     aGrabber.setInputStream ( xStream );
     123           0 : }
     124             : 
     125          16 : uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData )
     126             : {
     127          16 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext;
     128          16 :     if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA256_1K )
     129             :     {
     130          12 :         uno::Reference< uno::XComponentContext > xContext = xArgContext;
     131          12 :         if ( !xContext.is() )
     132           0 :             xContext = comphelper::getProcessComponentContext();
     133             : 
     134          12 :         uno::Reference< xml::crypto::XNSSInitializer > xDigestContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     135             : 
     136          12 :         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          16 :     return xDigestContext;
     142             : }
     143             : 
     144          28 : uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt )
     145             : {
     146          28 :     uno::Reference< xml::crypto::XCipherContext > xResult;
     147             : 
     148             :     try
     149             :     {
     150          28 :         if (xEncryptionData->m_nDerivedKeySize < 0)
     151             :         {
     152             :             throw ZipIOException("Invalid derived key length!",
     153           0 :                                   uno::Reference< XInterface >() );
     154             :         }
     155             : 
     156          28 :         uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize );
     157          56 :         if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ),
     158          28 :                             aDerivedKey.getLength(),
     159          28 :                             reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ),
     160          28 :                             xEncryptionData->m_aKey.getLength(),
     161          28 :                             reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ),
     162          28 :                             xEncryptionData->m_aSalt.getLength(),
     163         140 :                             xEncryptionData->m_nIterationCount ) )
     164             :         {
     165             :             throw ZipIOException("Can not create derived key!",
     166           0 :                                   uno::Reference< XInterface >() );
     167             :         }
     168             : 
     169          28 :         if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
     170             :         {
     171          20 :             uno::Reference< uno::XComponentContext > xContext = xArgContext;
     172          20 :             if ( !xContext.is() )
     173           0 :                 xContext = comphelper::getProcessComponentContext();
     174             : 
     175          20 :             uno::Reference< xml::crypto::XNSSInitializer > xCipherContextSupplier = xml::crypto::NSSInitializer::create( xContext );
     176             : 
     177          20 :             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          28 :         }
     188             :     }
     189           0 :     catch( ... )
     190             :     {
     191             :         OSL_ENSURE( sal_False, "Can not create cipher context!" );
     192             :     }
     193             : 
     194          28 :     return xResult;
     195             : }
     196             : 
     197           0 : void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData,
     198             :                                 sal_Int64 nSize,
     199             :                                 const ::rtl::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             :                                     ::rtl::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 = ::rtl::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(OSL_LOG_PREFIX, 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             : 
     399             :     // if we have a digest, then this file is an encrypted one and we should
     400             :     // check if we can decrypt it or not
     401             :     OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     402           0 :     if ( rData->m_aDigest.getLength() )
     403             :     {
     404           0 :         sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() );
     405           0 :         if ( nSize > n_ConstDigestLength + 32 )
     406           0 :             nSize = n_ConstDigestLength + 32;
     407             : 
     408             :         // skip header
     409           0 :         xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() +
     410           0 :                                 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() );
     411             : 
     412             :         // Only want to read enough to verify the digest
     413           0 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     414             : 
     415           0 :         xStream->readBytes( aReadBuffer, nSize );
     416             : 
     417           0 :         if ( !StaticHasValidPassword( rxContext, aReadBuffer, rData ) )
     418           0 :             throw packages::WrongPasswordException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     419             :     }
     420             : 
     421           0 :     return new XUnbufferedStream( rxContext, xStream, rData );
     422             : }
     423             : 
     424             : #if 0
     425             : // for debugging purposes
     426             : void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence )
     427             : {
     428             :     if ( aSequence.getLength() )
     429             :     {
     430             :         sal_Int32* pPointer = *( (sal_Int32**)&aSequence );
     431             :         sal_Int32 nSize = *( pPointer + 1 );
     432             :         sal_Int32 nMemSize = *( pPointer - 2 );
     433             :         sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) );
     434             :         OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" );
     435             :     }
     436             : }
     437             : #endif
     438             : 
     439          12 : sal_Bool ZipFile::StaticHasValidPassword( const uno::Reference< uno::XComponentContext >& rxContext, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData )
     440             : {
     441          12 :     if ( !rData.is() || !rData->m_aKey.getLength() )
     442           0 :         return sal_False;
     443             : 
     444          12 :     sal_Bool bRet = sal_False;
     445             : 
     446          12 :     uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( rxContext, rData, false ), uno::UNO_SET_THROW );
     447             : 
     448          12 :     uno::Sequence< sal_Int8 > aDecryptBuffer;
     449          12 :     uno::Sequence< sal_Int8 > aDecryptBuffer2;
     450             :     try
     451             :     {
     452          12 :         aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer );
     453          12 :         aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose();
     454             :     }
     455           8 :     catch( uno::Exception& )
     456             :     {
     457             :         // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream
     458             :         // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks )
     459             :     }
     460             : 
     461          12 :     if ( aDecryptBuffer2.getLength() )
     462             :     {
     463           0 :         sal_Int32 nOldLen = aDecryptBuffer.getLength();
     464           0 :         aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() );
     465           0 :         memcpy( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() );
     466             :     }
     467             : 
     468          12 :     if ( aDecryptBuffer.getLength() > n_ConstDigestLength )
     469           9 :         aDecryptBuffer.realloc( n_ConstDigestLength );
     470             : 
     471          12 :     uno::Sequence< sal_Int8 > aDigestSeq;
     472          12 :     uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( rxContext, rData ), uno::UNO_SET_THROW );
     473             : 
     474          12 :     xDigestContext->updateDigest( aDecryptBuffer );
     475          12 :     aDigestSeq = xDigestContext->finalizeDigestAndDispose();
     476             : 
     477             :     // If we don't have a digest, then we have to assume that the password is correct
     478          36 :     if (  rData->m_aDigest.getLength() != 0  &&
     479          12 :           ( aDigestSeq.getLength() != rData->m_aDigest.getLength() ||
     480          12 :             0 != memcmp ( aDigestSeq.getConstArray(),
     481          12 :                                      rData->m_aDigest.getConstArray(),
     482          24 :                                     aDigestSeq.getLength() ) ) )
     483             :     {
     484             :         // We should probably tell the user that the password they entered was wrong
     485             :     }
     486             :     else
     487          12 :         bRet = sal_True;
     488             : 
     489          12 :     return bRet;
     490             : }
     491             : 
     492          12 : sal_Bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< EncryptionData >& rData )
     493             : {
     494          12 :     ::osl::MutexGuard aGuard( m_aMutex );
     495             : 
     496          12 :     sal_Bool bRet = sal_False;
     497          12 :     if ( rData.is() && rData->m_aKey.getLength() )
     498             :     {
     499          12 :         xSeek->seek( rEntry.nOffset );
     500          12 :         sal_Int64 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize;
     501             : 
     502             :         // Only want to read enough to verify the digest
     503          12 :         if ( nSize > n_ConstDigestDecrypt )
     504           9 :             nSize = n_ConstDigestDecrypt;
     505             : 
     506          12 :         Sequence < sal_Int8 > aReadBuffer ( nSize );
     507             : 
     508          12 :         xStream->readBytes( aReadBuffer, nSize );
     509             : 
     510          12 :         bRet = StaticHasValidPassword( m_xContext, aReadBuffer, rData );
     511             :     }
     512             : 
     513          12 :     return bRet;
     514             : }
     515             : 
     516        2296 : uno::Reference< XInputStream > ZipFile::createUnbufferedStream(
     517             :             SotMutexHolderRef aMutexHolder,
     518             :             ZipEntry & rEntry,
     519             :             const ::rtl::Reference< EncryptionData > &rData,
     520             :             sal_Int8 nStreamMode,
     521             :             sal_Bool bIsEncrypted,
     522             :             ::rtl::OUString aMediaType )
     523             : {
     524        2296 :     ::osl::MutexGuard aGuard( m_aMutex );
     525             : 
     526        2296 :     return new XUnbufferedStream ( m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode );
     527             : }
     528             : 
     529             : 
     530         420 : ZipEnumeration * SAL_CALL ZipFile::entries(  )
     531             : {
     532         420 :     return new ZipEnumeration ( aEntries );
     533             : }
     534             : 
     535         325 : uno::Reference< XInputStream > SAL_CALL ZipFile::getInputStream( ZipEntry& rEntry,
     536             :         const ::rtl::Reference< EncryptionData > &rData,
     537             :         sal_Bool bIsEncrypted,
     538             :         SotMutexHolderRef aMutexHolder )
     539             :     throw(IOException, ZipException, RuntimeException)
     540             : {
     541         325 :     ::osl::MutexGuard aGuard( m_aMutex );
     542             : 
     543         325 :     if ( rEntry.nOffset <= 0 )
     544         325 :         readLOC( rEntry );
     545             : 
     546             :     // We want to return a rawStream if we either don't have a key or if the
     547             :     // key is wrong
     548             : 
     549         325 :     sal_Bool bNeedRawStream = rEntry.nMethod == STORED;
     550             : 
     551             :     // if we have a digest, then this file is an encrypted one and we should
     552             :     // check if we can decrypt it or not
     553         325 :     if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() )
     554           0 :         bNeedRawStream = !hasValidPassword ( rEntry, rData );
     555             : 
     556             :     return createUnbufferedStream ( aMutexHolder,
     557             :                                     rEntry,
     558             :                                     rData,
     559             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     560         325 :                                     bIsEncrypted );
     561             : }
     562             : 
     563        1971 : uno::Reference< XInputStream > SAL_CALL ZipFile::getDataStream( ZipEntry& rEntry,
     564             :         const ::rtl::Reference< EncryptionData > &rData,
     565             :         sal_Bool bIsEncrypted,
     566             :         SotMutexHolderRef aMutexHolder )
     567             :     throw ( packages::WrongPasswordException,
     568             :             IOException,
     569             :             ZipException,
     570             :             RuntimeException )
     571             : {
     572        1971 :     ::osl::MutexGuard aGuard( m_aMutex );
     573             : 
     574        1971 :     if ( rEntry.nOffset <= 0 )
     575        1517 :         readLOC( rEntry );
     576             : 
     577             :     // An exception must be thrown in case stream is encrypted and
     578             :     // there is no key or the key is wrong
     579        1971 :     sal_Bool bNeedRawStream = sal_False;
     580        1971 :     if ( bIsEncrypted )
     581             :     {
     582             :         // in case no digest is provided there is no way
     583             :         // to detect password correctness
     584          12 :         if ( !rData.is() )
     585             :             throw ZipException("Encrypted stream without encryption data!\n",
     586           0 :                                 uno::Reference< XInterface >() );
     587             : 
     588             :         // if we have a digest, then this file is an encrypted one and we should
     589             :         // check if we can decrypt it or not
     590             :         OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!\n" );
     591          12 :         if ( rData->m_aDigest.getLength() && !hasValidPassword ( rEntry, rData ) )
     592           0 :                 throw packages::WrongPasswordException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     593             :     }
     594             :     else
     595        1959 :         bNeedRawStream = ( rEntry.nMethod == STORED );
     596             : 
     597             :     return createUnbufferedStream ( aMutexHolder,
     598             :                                     rEntry,
     599             :                                     rData,
     600             :                                     bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
     601        1971 :                                     bIsEncrypted );
     602             : }
     603             : 
     604           0 : uno::Reference< XInputStream > SAL_CALL ZipFile::getRawData( ZipEntry& rEntry,
     605             :         const ::rtl::Reference< EncryptionData >& rData,
     606             :         sal_Bool bIsEncrypted,
     607             :         SotMutexHolderRef aMutexHolder )
     608             :     throw(IOException, ZipException, RuntimeException)
     609             : {
     610           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     611             : 
     612           0 :     if ( rEntry.nOffset <= 0 )
     613           0 :         readLOC( rEntry );
     614             : 
     615           0 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted );
     616             : }
     617             : 
     618           0 : uno::Reference< XInputStream > SAL_CALL ZipFile::getWrappedRawStream(
     619             :         ZipEntry& rEntry,
     620             :         const ::rtl::Reference< EncryptionData >& rData,
     621             :         const ::rtl::OUString& aMediaType,
     622             :         SotMutexHolderRef aMutexHolder )
     623             :     throw ( packages::NoEncryptionException,
     624             :             IOException,
     625             :             ZipException,
     626             :             RuntimeException )
     627             : {
     628           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     629             : 
     630           0 :     if ( !rData.is() )
     631           0 :         throw packages::NoEncryptionException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
     632             : 
     633           0 :     if ( rEntry.nOffset <= 0 )
     634           0 :         readLOC( rEntry );
     635             : 
     636           0 :     return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, sal_True, aMediaType );
     637             : }
     638             : 
     639        1842 : sal_Bool ZipFile::readLOC( ZipEntry &rEntry )
     640             :     throw(IOException, ZipException, RuntimeException)
     641             : {
     642        1842 :     ::osl::MutexGuard aGuard( m_aMutex );
     643             : 
     644             :     sal_Int32 nTestSig, nTime, nCRC, nSize, nCompressedSize;
     645             :     sal_Int16 nVersion, nFlag, nHow, nPathLen, nExtraLen;
     646        1842 :     sal_Int64 nPos = -rEntry.nOffset;
     647             : 
     648        1842 :     aGrabber.seek(nPos);
     649        1842 :     aGrabber >> nTestSig;
     650             : 
     651        1842 :     if (nTestSig != LOCSIG)
     652           0 :         throw ZipIOException("Invalid LOC header (bad signature)", uno::Reference < XInterface > () );
     653        1842 :     aGrabber >> nVersion;
     654        1842 :     aGrabber >> nFlag;
     655        1842 :     aGrabber >> nHow;
     656        1842 :     aGrabber >> nTime;
     657        1842 :     aGrabber >> nCRC;
     658        1842 :     aGrabber >> nCompressedSize;
     659        1842 :     aGrabber >> nSize;
     660        1842 :     aGrabber >> nPathLen;
     661        1842 :     aGrabber >> nExtraLen;
     662        1842 :     rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
     663             : 
     664             :     // FIXME64: need to read 64bit LOC
     665             : 
     666        1842 :     sal_Bool bBroken = sal_False;
     667             : 
     668             :     try
     669             :     {
     670             :         // read always in UTF8, some tools seem not to set UTF8 bit
     671        1842 :         uno::Sequence < sal_Int8 > aNameBuffer( nPathLen );
     672        1842 :         sal_Int32 nRead = aGrabber.readBytes( aNameBuffer, nPathLen );
     673        1842 :         if ( nRead < aNameBuffer.getLength() )
     674           0 :                 aNameBuffer.realloc( nRead );
     675             : 
     676        1842 :         ::rtl::OUString sLOCPath = rtl::OUString::intern( (sal_Char *) aNameBuffer.getArray(),
     677             :                                                           aNameBuffer.getLength(),
     678        3684 :                                                           RTL_TEXTENCODING_UTF8 );
     679             : 
     680        1842 :         if ( rEntry.nPathLen == -1 ) // the file was created
     681             :         {
     682           0 :             rEntry.nPathLen = nPathLen;
     683           0 :             rEntry.sPath = sLOCPath;
     684             :         }
     685             : 
     686             :         // check basic local file header / entry consistency, just
     687             :         // plain ignore bits 1 & 2 of the flag field - they are either
     688             :         // purely informative, or even fully undefined (depending on
     689             :         // nMethod)
     690             :         // Do *not* compare nMethod / nHow, older versions with
     691             :         // encrypted streams write mismatching DEFLATE/STORE pairs
     692             :         // there.
     693             :         // Do *not* compare timestamps, since MSO 2010 can produce documents
     694             :         // with timestamp difference in the central directory entry and local
     695             :         // file header.
     696             :         bBroken = rEntry.nVersion != nVersion
     697             :                         || (rEntry.nFlag & ~6L) != (nFlag & ~6L)
     698             :                         || rEntry.nPathLen != nPathLen
     699        1842 :                         || !rEntry.sPath.equals( sLOCPath );
     700             :     }
     701           0 :     catch(...)
     702             :     {
     703           0 :         bBroken = sal_True;
     704             :     }
     705             : 
     706        1842 :     if ( bBroken && !bRecoveryMode )
     707             :         throw ZipIOException("The stream seems to be broken!",
     708           0 :                             uno::Reference< XInterface >() );
     709             : 
     710        1842 :     return sal_True;
     711             : }
     712             : 
     713         420 : sal_Int32 ZipFile::findEND( )
     714             :     throw(IOException, ZipException, RuntimeException)
     715             : {
     716             :     // this method is called in constructor only, no need for mutex
     717             :     sal_Int32 nLength, nPos, nEnd;
     718         420 :     Sequence < sal_Int8 > aBuffer;
     719             :     try
     720             :     {
     721         420 :         nLength = static_cast <sal_Int32 > (aGrabber.getLength());
     722         420 :         if (nLength == 0 || nLength < ENDHDR)
     723           0 :             return -1;
     724         420 :         nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
     725         420 :         nEnd = nPos >= 0 ? nPos : 0 ;
     726             : 
     727         420 :         aGrabber.seek( nEnd );
     728         420 :         aGrabber.readBytes ( aBuffer, nLength - nEnd );
     729             : 
     730         420 :         const sal_Int8 *pBuffer = aBuffer.getConstArray();
     731             : 
     732         420 :         nPos = nLength - nEnd - ENDHDR;
     733         840 :         while ( nPos >= 0 )
     734             :         {
     735         420 :             if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
     736         420 :                 return nPos + nEnd;
     737           0 :             nPos--;
     738             :         }
     739             :     }
     740           0 :     catch ( IllegalArgumentException& )
     741             :     {
     742           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     743             :     }
     744           0 :     catch ( NotConnectedException& )
     745             :     {
     746           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     747             :     }
     748           0 :     catch ( BufferSizeExceededException& )
     749             :     {
     750           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     751             :     }
     752           0 :     throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
     753             : }
     754             : 
     755         420 : sal_Int32 ZipFile::readCEN()
     756             :     throw(IOException, ZipException, RuntimeException)
     757             : {
     758             :     // this method is called in constructor only, no need for mutex
     759         420 :     sal_Int32 nCenLen, nCenPos = -1, nCenOff, nEndPos, nLocPos;
     760             :     sal_uInt16 nCount, nTotal;
     761             : 
     762             :     try
     763             :     {
     764         420 :         nEndPos = findEND();
     765         420 :         if (nEndPos == -1)
     766           0 :             return -1;
     767         420 :         aGrabber.seek(nEndPos + ENDTOT);
     768         420 :         aGrabber >> nTotal;
     769         420 :         aGrabber >> nCenLen;
     770         420 :         aGrabber >> nCenOff;
     771             : 
     772         420 :         if ( nTotal * CENHDR > nCenLen )
     773           0 :             throw ZipException("invalid END header (bad entry count)", uno::Reference < XInterface > () );
     774             : 
     775         420 :         if ( nTotal > ZIP_MAXENTRIES )
     776           0 :             throw ZipException("too many entries in ZIP File", uno::Reference < XInterface > () );
     777             : 
     778         420 :         if ( nCenLen < 0 || nCenLen > nEndPos )
     779           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     780             : 
     781         420 :         nCenPos = nEndPos - nCenLen;
     782             : 
     783         420 :         if ( nCenOff < 0 || nCenOff > nCenPos )
     784           0 :             throw ZipException("Invalid END header (bad central directory size)", uno::Reference < XInterface > () );
     785             : 
     786         420 :         nLocPos = nCenPos - nCenOff;
     787         420 :         aGrabber.seek( nCenPos );
     788         420 :         Sequence < sal_Int8 > aCENBuffer ( nCenLen );
     789         420 :         sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
     790         420 :         if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
     791           0 :             throw ZipException ("Error reading CEN into memory buffer!", uno::Reference < XInterface > () );
     792             : 
     793         420 :         MemoryByteGrabber aMemGrabber ( aCENBuffer );
     794             : 
     795         420 :         ZipEntry aEntry;
     796             :         sal_Int32 nTestSig;
     797             :         sal_Int16 nCommentLen;
     798             : 
     799        6074 :         for (nCount = 0 ; nCount < nTotal; nCount++)
     800             :         {
     801        5654 :             aMemGrabber >> nTestSig;
     802        5654 :             if ( nTestSig != CENSIG )
     803           0 :                 throw ZipException("Invalid CEN header (bad signature)", uno::Reference < XInterface > () );
     804             : 
     805        5654 :             aMemGrabber.skipBytes ( 2 );
     806        5654 :             aMemGrabber >> aEntry.nVersion;
     807             : 
     808        5654 :             if ( ( aEntry.nVersion & 1 ) == 1 )
     809           0 :                 throw ZipException("Invalid CEN header (encrypted entry)", uno::Reference < XInterface > () );
     810             : 
     811        5654 :             aMemGrabber >> aEntry.nFlag;
     812        5654 :             aMemGrabber >> aEntry.nMethod;
     813             : 
     814        5654 :             if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED)
     815           0 :                 throw ZipException("Invalid CEN header (bad compression method)", uno::Reference < XInterface > () );
     816             : 
     817        5654 :             aMemGrabber >> aEntry.nTime;
     818        5654 :             aMemGrabber >> aEntry.nCrc;
     819             : 
     820             :             sal_uInt32 nCompressedSize, nSize, nOffset;
     821             : 
     822        5654 :             aMemGrabber >> nCompressedSize;
     823        5654 :             aMemGrabber >> nSize;
     824        5654 :             aMemGrabber >> aEntry.nPathLen;
     825        5654 :             aMemGrabber >> aEntry.nExtraLen;
     826        5654 :             aMemGrabber >> nCommentLen;
     827        5654 :             aMemGrabber.skipBytes ( 8 );
     828        5654 :             aMemGrabber >> nOffset;
     829             : 
     830             :             // FIXME64: need to read the 64bit header instead
     831        5654 :             if ( nSize == 0xffffffff ||
     832             :                  nOffset == 0xffffffff ||
     833             :                  nCompressedSize == 0xffffffff ) {
     834           0 :                 throw ZipException("PK64 zip file entry", uno::Reference < XInterface > () );
     835             :             } else {
     836        5654 :                 aEntry.nCompressedSize = nCompressedSize;
     837        5654 :                 aEntry.nSize = nSize;
     838        5654 :                 aEntry.nOffset = nOffset;
     839             :             }
     840             : 
     841        5654 :             aEntry.nOffset += nLocPos;
     842        5654 :             aEntry.nOffset *= -1;
     843             : 
     844        5654 :             if ( aEntry.nPathLen < 0 )
     845           0 :                 throw ZipException("unexpected name length", uno::Reference < XInterface > () );
     846             : 
     847        5654 :             if ( nCommentLen < 0 )
     848           0 :                 throw ZipException("unexpected comment length", uno::Reference < XInterface > () );
     849             : 
     850        5654 :             if ( aEntry.nExtraLen < 0 )
     851           0 :                 throw ZipException("unexpected extra header info length", uno::Reference < XInterface > () );
     852             : 
     853             :             // read always in UTF8, some tools seem not to set UTF8 bit
     854        5654 :             aEntry.sPath = rtl::OUString::intern ( (sal_Char *) aMemGrabber.getCurrentPos(),
     855             :                                                    aEntry.nPathLen,
     856       11308 :                                                    RTL_TEXTENCODING_UTF8 );
     857             : 
     858        5654 :             if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, sal_True ) )
     859           0 :                 throw ZipException("Zip entry has an invalid name.", uno::Reference < XInterface > () );
     860             : 
     861        5654 :             aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen );
     862        5654 :             aEntries[aEntry.sPath] = aEntry;
     863             :         }
     864             : 
     865         420 :         if (nCount != nTotal)
     866           0 :             throw ZipException("Count != Total", uno::Reference < XInterface > () );
     867             :     }
     868           0 :     catch ( IllegalArgumentException & )
     869             :     {
     870             :         // seek can throw this...
     871           0 :         nCenPos = -1; // make sure we return -1 to indicate an error
     872             :     }
     873         420 :     return nCenPos;
     874             : }
     875             : 
     876           0 : sal_Int32 ZipFile::recover()
     877             :     throw(IOException, ZipException, RuntimeException)
     878             : {
     879           0 :     ::osl::MutexGuard aGuard( m_aMutex );
     880             : 
     881             :     sal_Int64 nLength;
     882           0 :     Sequence < sal_Int8 > aBuffer;
     883           0 :     Sequence < sal_Int32 > aHeaderOffsets;
     884             : 
     885             :     try
     886             :     {
     887           0 :         nLength = aGrabber.getLength();
     888           0 :         if (nLength == 0 || nLength < ENDHDR)
     889           0 :             return -1;
     890             : 
     891           0 :         aGrabber.seek( 0 );
     892             : 
     893           0 :         const sal_Int64 nToRead = 32000;
     894           0 :         for( sal_Int64 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; )
     895             :         {
     896           0 :             const sal_Int8 *pBuffer = aBuffer.getConstArray();
     897           0 :             sal_Int32 nBufSize = aBuffer.getLength();
     898             : 
     899           0 :             sal_Int64 nPos = 0;
     900             :             // the buffer should contain at least one header,
     901             :             // or if it is end of the file, at least the postheader with sizes and hash
     902           0 :             while( nPos < nBufSize - 30
     903             :                 || ( nBufSize < nToRead && nPos < nBufSize - 16 ) )
     904             : 
     905             :             {
     906           0 :                 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 )
     907             :                 {
     908           0 :                     ZipEntry aEntry;
     909           0 :                     MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 26 ) );
     910             : 
     911           0 :                     aMemGrabber >> aEntry.nVersion;
     912           0 :                     if ( ( aEntry.nVersion & 1 ) != 1 )
     913             :                     {
     914           0 :                         aMemGrabber >> aEntry.nFlag;
     915           0 :                         aMemGrabber >> aEntry.nMethod;
     916             : 
     917           0 :                         if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED )
     918             :                         {
     919             :                             sal_uInt32 nCompressedSize, nSize;
     920             : 
     921           0 :                             aMemGrabber >> aEntry.nTime;
     922           0 :                             aMemGrabber >> aEntry.nCrc;
     923           0 :                             aMemGrabber >> nCompressedSize;
     924           0 :                             aMemGrabber >> nSize;
     925           0 :                             aMemGrabber >> aEntry.nPathLen;
     926           0 :                             aMemGrabber >> aEntry.nExtraLen;
     927             : 
     928             :                             // FIXME64: need to read the 64bit header instead
     929           0 :                             if ( nSize == 0xffffffff ||
     930             :                                  nCompressedSize == 0xffffffff ) {
     931           0 :                                 throw ZipException("PK64 zip file entry", uno::Reference < XInterface > () );
     932             :                             } else {
     933           0 :                                 aEntry.nCompressedSize = nCompressedSize;
     934           0 :                                 aEntry.nSize = nSize;
     935             :                             }
     936             : 
     937             :                             sal_Int32 nDescrLength =
     938           0 :                                 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 16 : 0;
     939             : 
     940           0 :                             sal_Int64 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize;
     941           0 :                             sal_Int64 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength;
     942           0 :                             if ( aEntry.nPathLen >= 0 && aEntry.nExtraLen >= 0
     943             :                                 && ( nGenPos + nPos + nBlockLength ) <= nLength )
     944             :                             {
     945             :                                 // read always in UTF8, some tools seem not to set UTF8 bit
     946           0 :                                 if( nPos + 30 + aEntry.nPathLen <= nBufSize )
     947           0 :                                     aEntry.sPath = OUString ( (sal_Char *) &pBuffer[nPos + 30],
     948             :                                                               aEntry.nPathLen,
     949           0 :                                                               RTL_TEXTENCODING_UTF8 );
     950             :                                 else
     951             :                                 {
     952           0 :                                     Sequence < sal_Int8 > aFileName;
     953           0 :                                     aGrabber.seek( nGenPos + nPos + 30 );
     954           0 :                                     aGrabber.readBytes( aFileName, aEntry.nPathLen );
     955           0 :                                     aEntry.sPath = OUString ( (sal_Char *) aFileName.getArray(),
     956             :                                                               aFileName.getLength(),
     957           0 :                                                               RTL_TEXTENCODING_UTF8 );
     958           0 :                                     aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength());
     959             :                                 }
     960             : 
     961           0 :                                 aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen;
     962             : 
     963           0 :                                 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) )
     964             :                                 {
     965           0 :                                     aEntry.nCrc = 0;
     966           0 :                                     aEntry.nCompressedSize = 0;
     967           0 :                                     aEntry.nSize = 0;
     968             :                                 }
     969             : 
     970           0 :                                 if ( aEntries.find( aEntry.sPath ) == aEntries.end() )
     971           0 :                                     aEntries[aEntry.sPath] = aEntry;
     972             :                             }
     973             :                         }
     974             :                     }
     975             : 
     976           0 :                     nPos += 4;
     977             :                 }
     978           0 :                 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 )
     979             :                 {
     980             :                     sal_Int32 nCRC32;
     981             :                     sal_uInt32 nCompressedSize32, nSize32;
     982             :                     sal_Int64 nCompressedSize, nSize;
     983           0 :                     MemoryByteGrabber aMemGrabber ( Sequence< sal_Int8 >( ((sal_Int8*)(&(pBuffer[nPos+4]))), 12 ) );
     984           0 :                     aMemGrabber >> nCRC32;
     985           0 :                     aMemGrabber >> nCompressedSize32;
     986           0 :                     aMemGrabber >> nSize32;
     987             : 
     988             :                     // FIXME64: work to be done here ...
     989           0 :                     nCompressedSize = nCompressedSize32;
     990           0 :                     nSize = nSize32;
     991             : 
     992           0 :                     for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); ++aIter )
     993             :                     {
     994           0 :                         ZipEntry aTmp = (*aIter).second;
     995             : 
     996             :                         // this is a broken package, accept this block not only for DEFLATED streams
     997           0 :                         if( (*aIter).second.nFlag & 8 )
     998             :                         {
     999           0 :                             sal_Int64 nStreamOffset = nGenPos + nPos - nCompressedSize;
    1000           0 :                             if ( nStreamOffset == (*aIter).second.nOffset && nCompressedSize > (*aIter).second.nCompressedSize )
    1001             :                             {
    1002             :                                 // only DEFLATED blocks need to be checked
    1003           0 :                                 sal_Bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize );
    1004             : 
    1005           0 :                                 if ( !bAcceptBlock )
    1006             :                                 {
    1007           0 :                                     sal_Int64 nRealSize = 0;
    1008           0 :                                     sal_Int32 nRealCRC = 0;
    1009           0 :                                     getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC );
    1010           0 :                                     bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 );
    1011             :                                 }
    1012             : 
    1013           0 :                                 if ( bAcceptBlock )
    1014             :                                 {
    1015           0 :                                     (*aIter).second.nCrc = nCRC32;
    1016           0 :                                     (*aIter).second.nCompressedSize = nCompressedSize;
    1017           0 :                                     (*aIter).second.nSize = nSize;
    1018             :                                 }
    1019             :                             }
    1020             : #if 0
    1021             : // for now ignore clearly broken streams
    1022             :                             else if( !(*aIter).second.nCompressedSize )
    1023             :                             {
    1024             :                                 (*aIter).second.nCrc = nCRC32;
    1025             :                                 sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nOffset;
    1026             :                                 (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nOffset;
    1027             :                                 (*aIter).second.nSize = nSize;
    1028             :                             }
    1029             : #endif
    1030             :                         }
    1031           0 :                     }
    1032             : 
    1033           0 :                     nPos += 4;
    1034             :                 }
    1035             :                 else
    1036           0 :                     nPos++;
    1037             :             }
    1038             : 
    1039           0 :             nGenPos += nPos;
    1040           0 :             aGrabber.seek( nGenPos );
    1041             :         }
    1042             : 
    1043           0 :         return 0;
    1044             :     }
    1045           0 :     catch ( IllegalArgumentException& )
    1046             :     {
    1047           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1048             :     }
    1049           0 :     catch ( NotConnectedException& )
    1050             :     {
    1051           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1052             :     }
    1053           0 :     catch ( BufferSizeExceededException& )
    1054             :     {
    1055           0 :         throw ZipException("Zip END signature not found!", uno::Reference < XInterface > () );
    1056           0 :     }
    1057             : }
    1058             : 
    1059           0 : sal_Bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry )
    1060             : {
    1061           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1062             : 
    1063           0 :     sal_Int32 nCRC = 0;
    1064           0 :     sal_Int64 nSize = 0;
    1065             : 
    1066           0 :     if( aEntry.nMethod == STORED )
    1067           0 :         return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc );
    1068             : 
    1069           0 :     getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC );
    1070           0 :     return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC );
    1071             : }
    1072             : 
    1073           0 : sal_Int32 ZipFile::getCRC( sal_Int64 nOffset, sal_Int64 nSize )
    1074             : {
    1075           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1076             : 
    1077           0 :     Sequence < sal_Int8 > aBuffer;
    1078           0 :     CRC32 aCRC;
    1079           0 :     sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nSize, static_cast< sal_Int64 >( 32000 ) ) );
    1080             : 
    1081           0 :     aGrabber.seek( nOffset );
    1082           0 :     for ( int ind = 0;
    1083           0 :           aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize;
    1084             :           ind++ )
    1085             :     {
    1086             :         sal_Int64 nLen = ::std::min( static_cast< sal_Int64 >( nBlockSize ),
    1087           0 :                                      nSize - ind * nBlockSize );
    1088           0 :         aCRC.updateSegment( aBuffer, 0, static_cast< sal_Int32 >( nLen ) );
    1089             :     }
    1090             : 
    1091           0 :     return aCRC.getValue();
    1092             : }
    1093             : 
    1094           0 : void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_Int64 *nSize, sal_Int32 *nCRC )
    1095             : {
    1096           0 :     ::osl::MutexGuard aGuard( m_aMutex );
    1097             : 
    1098           0 :     Sequence < sal_Int8 > aBuffer;
    1099           0 :     CRC32 aCRC;
    1100           0 :     sal_Int64 nRealSize = 0;
    1101           0 :     Inflater aInflaterLocal( sal_True );
    1102           0 :     sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nCompressedSize, static_cast< sal_Int64 >( 32000 ) ) );
    1103             : 
    1104           0 :     aGrabber.seek( nOffset );
    1105           0 :     for ( int ind = 0;
    1106           0 :           !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize;
    1107             :           ind++ )
    1108             :     {
    1109           0 :         Sequence < sal_Int8 > aData( nBlockSize );
    1110           0 :         sal_Int32 nLastInflated = 0;
    1111           0 :         sal_Int64 nInBlock = 0;
    1112             : 
    1113           0 :         aInflaterLocal.setInput( aBuffer );
    1114           0 :         do
    1115             :         {
    1116           0 :             nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize );
    1117           0 :             aCRC.updateSegment( aData, 0, nLastInflated );
    1118           0 :             nInBlock += nLastInflated;
    1119           0 :         } while( !aInflater.finished() && nLastInflated );
    1120             : 
    1121           0 :         nRealSize += nInBlock;
    1122           0 :     }
    1123             : 
    1124           0 :     *nSize = nRealSize;
    1125           0 :     *nCRC = aCRC.getValue();
    1126           0 : }
    1127             : 
    1128             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10