Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / package / source / zipapi / ZipFile.cxx
blob8126ebba305b25de92ce64aa10751857ad53a69b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
31 #include <comphelper/storagehelper.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <rtl/digest.h>
34 #include <osl/diagnose.h>
35 #include <o3tl/make_unique.hxx>
37 #include <algorithm>
38 #include <iterator>
39 #include <memory>
40 #include <vector>
42 #include "blowfishcontext.hxx"
43 #include "sha1context.hxx"
44 #include <ZipFile.hxx>
45 #include <ZipEnumeration.hxx>
46 #include "XUnbufferedStream.hxx"
47 #include "XBufferedThreadedStream.hxx"
48 #include <PackageConstants.hxx>
49 #include <EncryptedDataHeader.hxx>
50 #include <EncryptionData.hxx>
51 #include "MemoryByteGrabber.hxx"
53 #include <CRC32.hxx>
55 using namespace com::sun::star;
56 using namespace com::sun::star::io;
57 using namespace com::sun::star::uno;
58 using namespace com::sun::star::ucb;
59 using namespace com::sun::star::lang;
60 using namespace com::sun::star::packages;
61 using namespace com::sun::star::packages::zip;
62 using namespace com::sun::star::packages::zip::ZipConstants;
64 using ZipUtils::Inflater;
66 #if OSL_DEBUG_LEVEL > 0
67 #define THROW_WHERE SAL_WHERE
68 #else
69 #define THROW_WHERE ""
70 #endif
72 /** This class is used to read entries from a zip file
74 ZipFile::ZipFile( const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder,
75 uno::Reference < XInputStream > const &xInput,
76 const uno::Reference < XComponentContext > & rxContext,
77 bool bInitialise )
78 : m_aMutexHolder( aMutexHolder )
79 , aGrabber( xInput )
80 , aInflater( true )
81 , xStream(xInput)
82 , m_xContext ( rxContext )
83 , bRecoveryMode( false )
85 if (bInitialise)
87 if ( readCEN() == -1 )
89 aEntries.clear();
90 throw ZipException( "stream data looks to be broken" );
95 ZipFile::ZipFile( const rtl::Reference< comphelper::RefCountedMutex >& aMutexHolder,
96 uno::Reference < XInputStream > const &xInput,
97 const uno::Reference < XComponentContext > & rxContext,
98 bool bInitialise, bool bForceRecovery)
99 : m_aMutexHolder( aMutexHolder )
100 , aGrabber( xInput )
101 , aInflater( true )
102 , xStream(xInput)
103 , m_xContext ( rxContext )
104 , bRecoveryMode( bForceRecovery )
106 if (bInitialise)
108 if ( bForceRecovery )
110 recover();
112 else if ( readCEN() == -1 )
114 aEntries.clear();
115 throw ZipException("stream data looks to be broken" );
120 ZipFile::~ZipFile()
122 aEntries.clear();
125 void ZipFile::setInputStream ( const uno::Reference < XInputStream >& xNewStream )
127 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
129 xStream = xNewStream;
130 aGrabber.setInputStream ( xStream );
133 uno::Reference< xml::crypto::XDigestContext > ZipFile::StaticGetDigestContextForChecksum( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData )
135 uno::Reference< xml::crypto::XDigestContext > xDigestContext;
136 if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA256_1K )
138 uno::Reference< uno::XComponentContext > xContext = xArgContext;
139 if ( !xContext.is() )
140 xContext = comphelper::getProcessComponentContext();
142 uno::Reference< xml::crypto::XNSSInitializer > xDigestContextSupplier = xml::crypto::NSSInitializer::create( xContext );
144 xDigestContext.set( xDigestContextSupplier->getDigestContext( xEncryptionData->m_nCheckAlg, uno::Sequence< beans::NamedValue >() ), uno::UNO_SET_THROW );
146 else if ( xEncryptionData->m_nCheckAlg == xml::crypto::DigestID::SHA1_1K )
148 if (xEncryptionData->m_bTryWrongSHA1)
150 xDigestContext.set(StarOfficeSHA1DigestContext::Create(), uno::UNO_SET_THROW);
152 else
154 xDigestContext.set(CorrectSHA1DigestContext::Create(), uno::UNO_SET_THROW);
158 return xDigestContext;
161 uno::Reference< xml::crypto::XCipherContext > ZipFile::StaticGetCipher( const uno::Reference< uno::XComponentContext >& xArgContext, const ::rtl::Reference< EncryptionData >& xEncryptionData, bool bEncrypt )
163 uno::Reference< xml::crypto::XCipherContext > xResult;
165 if (xEncryptionData->m_nDerivedKeySize < 0)
167 throw ZipIOException("Invalid derived key length!" );
170 uno::Sequence< sal_Int8 > aDerivedKey( xEncryptionData->m_nDerivedKeySize );
171 if ( !xEncryptionData->m_nIterationCount &&
172 xEncryptionData->m_nDerivedKeySize == xEncryptionData->m_aKey.getLength() )
174 // gpg4libre: no need to derive key, m_aKey is already
175 // usable as symmetric session key
176 aDerivedKey = xEncryptionData->m_aKey;
178 else if ( rtl_Digest_E_None != rtl_digest_PBKDF2( reinterpret_cast< sal_uInt8* >( aDerivedKey.getArray() ),
179 aDerivedKey.getLength(),
180 reinterpret_cast< const sal_uInt8 * > (xEncryptionData->m_aKey.getConstArray() ),
181 xEncryptionData->m_aKey.getLength(),
182 reinterpret_cast< const sal_uInt8 * > ( xEncryptionData->m_aSalt.getConstArray() ),
183 xEncryptionData->m_aSalt.getLength(),
184 xEncryptionData->m_nIterationCount ) )
186 throw ZipIOException("Can not create derived key!" );
189 if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING )
191 uno::Reference< uno::XComponentContext > xContext = xArgContext;
192 if ( !xContext.is() )
193 xContext = comphelper::getProcessComponentContext();
195 uno::Reference< xml::crypto::XNSSInitializer > xCipherContextSupplier = xml::crypto::NSSInitializer::create( xContext );
197 xResult = xCipherContextSupplier->getCipherContext( xEncryptionData->m_nEncAlg, aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt, uno::Sequence< beans::NamedValue >() );
199 else if ( xEncryptionData->m_nEncAlg == xml::crypto::CipherID::BLOWFISH_CFB_8 )
201 xResult = BlowfishCFB8CipherContext::Create( aDerivedKey, xEncryptionData->m_aInitVector, bEncrypt );
203 else
205 throw ZipIOException("Unknown cipher algorithm is requested!" );
208 return xResult;
211 void ZipFile::StaticFillHeader( const ::rtl::Reference< EncryptionData >& rData,
212 sal_Int64 nSize,
213 const OUString& aMediaType,
214 sal_Int8 * & pHeader )
216 // I think it's safe to restrict vector and salt length to 2 bytes !
217 sal_Int16 nIVLength = static_cast < sal_Int16 > ( rData->m_aInitVector.getLength() );
218 sal_Int16 nSaltLength = static_cast < sal_Int16 > ( rData->m_aSalt.getLength() );
219 sal_Int16 nDigestLength = static_cast < sal_Int16 > ( rData->m_aDigest.getLength() );
220 sal_Int16 nMediaTypeLength = static_cast < sal_Int16 > ( aMediaType.getLength() * sizeof( sal_Unicode ) );
222 // First the header
223 *(pHeader++) = ( n_ConstHeader >> 0 ) & 0xFF;
224 *(pHeader++) = ( n_ConstHeader >> 8 ) & 0xFF;
225 *(pHeader++) = ( n_ConstHeader >> 16 ) & 0xFF;
226 *(pHeader++) = ( n_ConstHeader >> 24 ) & 0xFF;
228 // Then the version
229 *(pHeader++) = ( n_ConstCurrentVersion >> 0 ) & 0xFF;
230 *(pHeader++) = ( n_ConstCurrentVersion >> 8 ) & 0xFF;
232 // Then the iteration Count
233 sal_Int32 nIterationCount = rData->m_nIterationCount;
234 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 0 ) & 0xFF);
235 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 8 ) & 0xFF);
236 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 16 ) & 0xFF);
237 *(pHeader++) = static_cast< sal_Int8 >(( nIterationCount >> 24 ) & 0xFF);
239 // FIXME64: need to handle larger sizes
240 // Then the size:
241 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 0 ) & 0xFF);
242 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 8 ) & 0xFF);
243 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 16 ) & 0xFF);
244 *(pHeader++) = static_cast< sal_Int8 >(( nSize >> 24 ) & 0xFF);
246 // Then the encryption algorithm
247 sal_Int32 nEncAlgID = rData->m_nEncAlg;
248 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 0 ) & 0xFF);
249 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 8 ) & 0xFF);
250 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 16 ) & 0xFF);
251 *(pHeader++) = static_cast< sal_Int8 >(( nEncAlgID >> 24 ) & 0xFF);
253 // Then the checksum algorithm
254 sal_Int32 nChecksumAlgID = rData->m_nCheckAlg;
255 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 0 ) & 0xFF);
256 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 8 ) & 0xFF);
257 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 16 ) & 0xFF);
258 *(pHeader++) = static_cast< sal_Int8 >(( nChecksumAlgID >> 24 ) & 0xFF);
260 // Then the derived key size
261 sal_Int32 nDerivedKeySize = rData->m_nDerivedKeySize;
262 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 0 ) & 0xFF);
263 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 8 ) & 0xFF);
264 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 16 ) & 0xFF);
265 *(pHeader++) = static_cast< sal_Int8 >(( nDerivedKeySize >> 24 ) & 0xFF);
267 // Then the start key generation algorithm
268 sal_Int32 nKeyAlgID = rData->m_nStartKeyGenID;
269 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 0 ) & 0xFF);
270 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 8 ) & 0xFF);
271 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 16 ) & 0xFF);
272 *(pHeader++) = static_cast< sal_Int8 >(( nKeyAlgID >> 24 ) & 0xFF);
274 // Then the salt length
275 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 0 ) & 0xFF);
276 *(pHeader++) = static_cast< sal_Int8 >(( nSaltLength >> 8 ) & 0xFF);
278 // Then the IV length
279 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 0 ) & 0xFF);
280 *(pHeader++) = static_cast< sal_Int8 >(( nIVLength >> 8 ) & 0xFF);
282 // Then the digest length
283 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 0 ) & 0xFF);
284 *(pHeader++) = static_cast< sal_Int8 >(( nDigestLength >> 8 ) & 0xFF);
286 // Then the mediatype length
287 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 0 ) & 0xFF);
288 *(pHeader++) = static_cast< sal_Int8 >(( nMediaTypeLength >> 8 ) & 0xFF);
290 // Then the salt content
291 memcpy ( pHeader, rData->m_aSalt.getConstArray(), nSaltLength );
292 pHeader += nSaltLength;
294 // Then the IV content
295 memcpy ( pHeader, rData->m_aInitVector.getConstArray(), nIVLength );
296 pHeader += nIVLength;
298 // Then the digest content
299 memcpy ( pHeader, rData->m_aDigest.getConstArray(), nDigestLength );
300 pHeader += nDigestLength;
302 // Then the mediatype itself
303 memcpy ( pHeader, aMediaType.getStr(), nMediaTypeLength );
304 pHeader += nMediaTypeLength;
307 bool ZipFile::StaticFillData ( ::rtl::Reference< BaseEncryptionData > const & rData,
308 sal_Int32 &rEncAlg,
309 sal_Int32 &rChecksumAlg,
310 sal_Int32 &rDerivedKeySize,
311 sal_Int32 &rStartKeyGenID,
312 sal_Int32 &rSize,
313 OUString& aMediaType,
314 const uno::Reference< XInputStream >& rStream )
316 bool bOk = false;
317 const sal_Int32 nHeaderSize = n_ConstHeaderSize - 4;
318 Sequence < sal_Int8 > aBuffer ( nHeaderSize );
319 if ( nHeaderSize == rStream->readBytes ( aBuffer, nHeaderSize ) )
321 sal_Int16 nPos = 0;
322 sal_Int8 *pBuffer = aBuffer.getArray();
323 sal_Int16 nVersion = pBuffer[nPos++] & 0xFF;
324 nVersion |= ( pBuffer[nPos++] & 0xFF ) << 8;
325 if ( nVersion == n_ConstCurrentVersion )
327 sal_Int32 nCount = pBuffer[nPos++] & 0xFF;
328 nCount |= ( pBuffer[nPos++] & 0xFF ) << 8;
329 nCount |= ( pBuffer[nPos++] & 0xFF ) << 16;
330 nCount |= ( pBuffer[nPos++] & 0xFF ) << 24;
331 rData->m_nIterationCount = nCount;
333 rSize = pBuffer[nPos++] & 0xFF;
334 rSize |= ( pBuffer[nPos++] & 0xFF ) << 8;
335 rSize |= ( pBuffer[nPos++] & 0xFF ) << 16;
336 rSize |= ( pBuffer[nPos++] & 0xFF ) << 24;
338 rEncAlg = pBuffer[nPos++] & 0xFF;
339 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 8;
340 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 16;
341 rEncAlg |= ( pBuffer[nPos++] & 0xFF ) << 24;
343 rChecksumAlg = pBuffer[nPos++] & 0xFF;
344 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 8;
345 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 16;
346 rChecksumAlg |= ( pBuffer[nPos++] & 0xFF ) << 24;
348 rDerivedKeySize = pBuffer[nPos++] & 0xFF;
349 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 8;
350 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 16;
351 rDerivedKeySize |= ( pBuffer[nPos++] & 0xFF ) << 24;
353 rStartKeyGenID = pBuffer[nPos++] & 0xFF;
354 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 8;
355 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 16;
356 rStartKeyGenID |= ( pBuffer[nPos++] & 0xFF ) << 24;
358 sal_Int16 nSaltLength = pBuffer[nPos++] & 0xFF;
359 nSaltLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
360 sal_Int16 nIVLength = ( pBuffer[nPos++] & 0xFF );
361 nIVLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
362 sal_Int16 nDigestLength = pBuffer[nPos++] & 0xFF;
363 nDigestLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
365 sal_Int16 nMediaTypeLength = pBuffer[nPos++] & 0xFF;
366 nMediaTypeLength |= ( pBuffer[nPos++] & 0xFF ) << 8;
368 if ( nSaltLength == rStream->readBytes ( aBuffer, nSaltLength ) )
370 rData->m_aSalt.realloc ( nSaltLength );
371 memcpy ( rData->m_aSalt.getArray(), aBuffer.getConstArray(), nSaltLength );
372 if ( nIVLength == rStream->readBytes ( aBuffer, nIVLength ) )
374 rData->m_aInitVector.realloc ( nIVLength );
375 memcpy ( rData->m_aInitVector.getArray(), aBuffer.getConstArray(), nIVLength );
376 if ( nDigestLength == rStream->readBytes ( aBuffer, nDigestLength ) )
378 rData->m_aDigest.realloc ( nDigestLength );
379 memcpy ( rData->m_aDigest.getArray(), aBuffer.getConstArray(), nDigestLength );
381 if ( nMediaTypeLength == rStream->readBytes ( aBuffer, nMediaTypeLength ) )
383 aMediaType = OUString( reinterpret_cast<sal_Unicode const *>(aBuffer.getConstArray()),
384 nMediaTypeLength / sizeof( sal_Unicode ) );
385 bOk = true;
392 return bOk;
395 uno::Reference< XInputStream > ZipFile::StaticGetDataFromRawStream( const rtl::Reference< comphelper::RefCountedMutex >& aMutexHolder,
396 const uno::Reference< uno::XComponentContext >& rxContext,
397 const uno::Reference< XInputStream >& xStream,
398 const ::rtl::Reference< EncryptionData > &rData )
400 if ( !rData.is() )
401 throw ZipIOException("Encrypted stream without encryption data!" );
403 if ( !rData->m_aKey.getLength() )
404 throw packages::WrongPasswordException(THROW_WHERE );
406 uno::Reference< XSeekable > xSeek( xStream, UNO_QUERY );
407 if ( !xSeek.is() )
408 throw ZipIOException("The stream must be seekable!" );
410 // if we have a digest, then this file is an encrypted one and we should
411 // check if we can decrypt it or not
412 OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!" );
413 if ( rData->m_aDigest.getLength() )
415 sal_Int32 nSize = sal::static_int_cast< sal_Int32 >( xSeek->getLength() );
416 if ( nSize > n_ConstDigestLength + 32 )
417 nSize = n_ConstDigestLength + 32;
419 // skip header
420 xSeek->seek( n_ConstHeaderSize + rData->m_aInitVector.getLength() +
421 rData->m_aSalt.getLength() + rData->m_aDigest.getLength() );
423 // Only want to read enough to verify the digest
424 Sequence < sal_Int8 > aReadBuffer ( nSize );
426 xStream->readBytes( aReadBuffer, nSize );
428 if ( !StaticHasValidPassword( rxContext, aReadBuffer, rData ) )
429 throw packages::WrongPasswordException(THROW_WHERE );
432 return new XUnbufferedStream( aMutexHolder, xStream, rData );
435 #if 0
436 // for debugging purposes
437 void CheckSequence( const uno::Sequence< sal_Int8 >& aSequence )
439 if ( aSequence.getLength() )
441 sal_Int32* pPointer = *( (sal_Int32**)&aSequence );
442 sal_Int32 nSize = *( pPointer + 1 );
443 sal_Int32 nMemSize = *( pPointer - 2 );
444 sal_Int32 nUsedMemSize = ( nSize + 4 * sizeof( sal_Int32 ) );
445 OSL_ENSURE( nSize == aSequence.getLength() && nUsedMemSize + 7 - ( nUsedMemSize - 1 ) % 8 == nMemSize, "Broken Sequence!" );
448 #endif
450 bool ZipFile::StaticHasValidPassword( const uno::Reference< uno::XComponentContext >& rxContext, const Sequence< sal_Int8 > &aReadBuffer, const ::rtl::Reference< EncryptionData > &rData )
452 if ( !rData.is() || !rData->m_aKey.getLength() )
453 return false;
455 bool bRet = false;
457 uno::Reference< xml::crypto::XCipherContext > xCipher( StaticGetCipher( rxContext, rData, false ), uno::UNO_SET_THROW );
459 uno::Sequence< sal_Int8 > aDecryptBuffer;
460 uno::Sequence< sal_Int8 > aDecryptBuffer2;
463 aDecryptBuffer = xCipher->convertWithCipherContext( aReadBuffer );
464 aDecryptBuffer2 = xCipher->finalizeCipherContextAndDispose();
466 catch( uno::Exception& )
468 // decryption with padding will throw the exception in finalizing if the buffer represent only part of the stream
469 // it is no problem, actually this is why we read 32 additional bytes ( two of maximal possible encryption blocks )
472 if ( aDecryptBuffer2.getLength() )
474 sal_Int32 nOldLen = aDecryptBuffer.getLength();
475 aDecryptBuffer.realloc( nOldLen + aDecryptBuffer2.getLength() );
476 memcpy( aDecryptBuffer.getArray() + nOldLen, aDecryptBuffer2.getArray(), aDecryptBuffer2.getLength() );
479 if ( aDecryptBuffer.getLength() > n_ConstDigestLength )
480 aDecryptBuffer.realloc( n_ConstDigestLength );
482 uno::Sequence< sal_Int8 > aDigestSeq;
483 uno::Reference< xml::crypto::XDigestContext > xDigestContext( StaticGetDigestContextForChecksum( rxContext, rData ), uno::UNO_SET_THROW );
485 xDigestContext->updateDigest( aDecryptBuffer );
486 aDigestSeq = xDigestContext->finalizeDigestAndDispose();
488 // If we don't have a digest, then we have to assume that the password is correct
489 if ( rData->m_aDigest.getLength() != 0 &&
490 ( aDigestSeq.getLength() != rData->m_aDigest.getLength() ||
491 0 != memcmp ( aDigestSeq.getConstArray(),
492 rData->m_aDigest.getConstArray(),
493 aDigestSeq.getLength() ) ) )
495 // We should probably tell the user that the password they entered was wrong
497 else
498 bRet = true;
500 return bRet;
503 bool ZipFile::hasValidPassword ( ZipEntry const & rEntry, const ::rtl::Reference< EncryptionData >& rData )
505 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
507 bool bRet = false;
508 if ( rData.is() && rData->m_aKey.getLength() )
510 css::uno::Reference < css::io::XSeekable > xSeek(xStream, UNO_QUERY_THROW);
511 xSeek->seek( rEntry.nOffset );
512 sal_Int64 nSize = rEntry.nMethod == DEFLATED ? rEntry.nCompressedSize : rEntry.nSize;
514 // Only want to read enough to verify the digest
515 if ( nSize > n_ConstDigestDecrypt )
516 nSize = n_ConstDigestDecrypt;
518 Sequence < sal_Int8 > aReadBuffer ( nSize );
520 xStream->readBytes( aReadBuffer, nSize );
522 bRet = StaticHasValidPassword( m_xContext, aReadBuffer, rData );
525 return bRet;
528 namespace {
530 class XBufferedStream : public cppu::WeakImplHelper<css::io::XInputStream>
532 std::vector<sal_Int8> maBytes;
533 size_t mnPos;
535 size_t remainingSize() const
537 return maBytes.size() - mnPos;
540 bool hasBytes() const
542 return mnPos < maBytes.size();
545 public:
546 XBufferedStream( const uno::Reference<XInputStream>& xSrcStream ) : mnPos(0)
548 const sal_Int32 nBufSize = 8192;
550 sal_Int32 nRemaining = xSrcStream->available();
551 sal_Int32 nRead = 0;
552 maBytes.reserve(nRemaining);
553 uno::Sequence<sal_Int8> aBuf(nBufSize);
555 auto readAndCopy = [&]( sal_Int32 nReadSize ) -> sal_Int32
557 sal_Int32 nBytes = xSrcStream->readBytes(aBuf, nReadSize);
558 const sal_Int8* p = aBuf.getArray();
559 const sal_Int8* pEnd = p + nBytes;
560 std::copy(p, pEnd, std::back_inserter(maBytes));
561 return nBytes;
564 while (nRemaining > nBufSize)
566 const auto nBytes = readAndCopy(nBufSize);
567 if (!nBytes)
568 break;
569 nRead += nBytes;
570 nRemaining -= nBytes;
573 if (nRemaining)
574 nRead += readAndCopy(nRemaining);
575 maBytes.resize(nRead);
578 virtual sal_Int32 SAL_CALL readBytes( uno::Sequence<sal_Int8>& rData, sal_Int32 nBytesToRead ) override
580 if (!hasBytes())
581 return 0;
583 sal_Int32 nReadSize = std::min<sal_Int32>(nBytesToRead, remainingSize());
584 rData.realloc(nReadSize);
585 std::vector<sal_Int8>::const_iterator it = maBytes.cbegin();
586 std::advance(it, mnPos);
587 for (sal_Int32 i = 0; i < nReadSize; ++i, ++it)
588 rData[i] = *it;
590 mnPos += nReadSize;
592 return nReadSize;
595 virtual sal_Int32 SAL_CALL readSomeBytes( ::css::uno::Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead ) override
597 return readBytes(rData, nMaxBytesToRead);
600 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override
602 if (!hasBytes())
603 return;
605 mnPos += nBytesToSkip;
608 virtual sal_Int32 SAL_CALL available() override
610 if (!hasBytes())
611 return 0;
613 return remainingSize();
616 virtual void SAL_CALL closeInput() override
623 uno::Reference< XInputStream > ZipFile::createStreamForZipEntry(
624 const rtl::Reference< comphelper::RefCountedMutex >& aMutexHolder,
625 ZipEntry const & rEntry,
626 const ::rtl::Reference< EncryptionData > &rData,
627 sal_Int8 nStreamMode,
628 bool bIsEncrypted,
629 const bool bUseBufferedStream,
630 const OUString& aMediaType )
632 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
634 rtl::Reference< XUnbufferedStream > xSrcStream = new XUnbufferedStream(
635 m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode);
637 if (!bUseBufferedStream)
638 return xSrcStream.get();
640 uno::Reference<io::XInputStream> xBufStream;
641 static const sal_Int32 nThreadingThreshold = 10000;
643 if( xSrcStream->available() > nThreadingThreshold )
644 xBufStream = new XBufferedThreadedStream(xSrcStream.get(), xSrcStream->getSize());
645 else
646 xBufStream = new XBufferedStream(xSrcStream.get());
648 return xBufStream;
651 std::unique_ptr<ZipEnumeration> ZipFile::entries()
653 return o3tl::make_unique<ZipEnumeration>(aEntries);
656 uno::Reference< XInputStream > ZipFile::getInputStream( ZipEntry& rEntry,
657 const ::rtl::Reference< EncryptionData > &rData,
658 bool bIsEncrypted,
659 const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder )
661 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
663 if ( rEntry.nOffset <= 0 )
664 readLOC( rEntry );
666 // We want to return a rawStream if we either don't have a key or if the
667 // key is wrong
669 bool bNeedRawStream = rEntry.nMethod == STORED;
671 // if we have a digest, then this file is an encrypted one and we should
672 // check if we can decrypt it or not
673 if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() )
674 bNeedRawStream = !hasValidPassword ( rEntry, rData );
676 return createStreamForZipEntry ( aMutexHolder,
677 rEntry,
678 rData,
679 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
680 bIsEncrypted );
683 uno::Reference< XInputStream > ZipFile::getDataStream( ZipEntry& rEntry,
684 const ::rtl::Reference< EncryptionData > &rData,
685 bool bIsEncrypted,
686 const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder )
688 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
690 if ( rEntry.nOffset <= 0 )
691 readLOC( rEntry );
693 // An exception must be thrown in case stream is encrypted and
694 // there is no key or the key is wrong
695 bool bNeedRawStream = false;
696 if ( bIsEncrypted )
698 // in case no digest is provided there is no way
699 // to detect password correctness
700 if ( !rData.is() )
701 throw ZipException("Encrypted stream without encryption data!" );
703 // if we have a digest, then this file is an encrypted one and we should
704 // check if we can decrypt it or not
705 OSL_ENSURE( rData->m_aDigest.getLength(), "Can't detect password correctness without digest!" );
706 if ( rData->m_aDigest.getLength() && !hasValidPassword ( rEntry, rData ) )
707 throw packages::WrongPasswordException(THROW_WHERE );
709 else
710 bNeedRawStream = ( rEntry.nMethod == STORED );
712 return createStreamForZipEntry ( aMutexHolder,
713 rEntry,
714 rData,
715 bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
716 bIsEncrypted );
719 uno::Reference< XInputStream > ZipFile::getRawData( ZipEntry& rEntry,
720 const ::rtl::Reference< EncryptionData >& rData,
721 bool bIsEncrypted,
722 const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder,
723 const bool bUseBufferedStream )
725 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
727 if ( rEntry.nOffset <= 0 )
728 readLOC( rEntry );
730 return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted, bUseBufferedStream );
733 uno::Reference< XInputStream > ZipFile::getWrappedRawStream(
734 ZipEntry& rEntry,
735 const ::rtl::Reference< EncryptionData >& rData,
736 const OUString& aMediaType,
737 const rtl::Reference<comphelper::RefCountedMutex>& aMutexHolder )
739 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
741 if ( !rData.is() )
742 throw packages::NoEncryptionException(THROW_WHERE );
744 if ( rEntry.nOffset <= 0 )
745 readLOC( rEntry );
747 return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, true, true, aMediaType );
750 bool ZipFile::readLOC( ZipEntry &rEntry )
752 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
754 sal_Int64 nPos = -rEntry.nOffset;
756 aGrabber.seek(nPos);
757 sal_Int32 nTestSig = aGrabber.ReadInt32();
758 if (nTestSig != LOCSIG)
759 throw ZipIOException("Invalid LOC header (bad signature)" );
761 // Ignore all (duplicated) information from the local file header.
762 // various programs produced "broken" zip files; even LO at some point.
763 // Just verify the path and calculate the data offset and otherwise
764 // rely on the central directory info.
766 aGrabber.ReadInt16(); //version
767 aGrabber.ReadInt16(); //flag
768 aGrabber.ReadInt16(); //how
769 aGrabber.ReadInt32(); //time
770 aGrabber.ReadInt32(); //crc
771 aGrabber.ReadInt32(); //compressed size
772 aGrabber.ReadInt32(); //size
773 sal_Int16 nPathLen = aGrabber.ReadInt16();
774 sal_Int16 nExtraLen = aGrabber.ReadInt16();
775 rEntry.nOffset = aGrabber.getPosition() + nPathLen + nExtraLen;
777 // FIXME64: need to read 64bit LOC
779 bool bBroken = false;
783 sal_Int16 nPathLenToRead = nPathLen;
784 const sal_Int64 nBytesAvailable = aGrabber.getLength() - aGrabber.getPosition();
785 if (nPathLenToRead > nBytesAvailable)
786 nPathLenToRead = nBytesAvailable;
787 else if (nPathLenToRead < 0)
788 nPathLenToRead = 0;
790 // read always in UTF8, some tools seem not to set UTF8 bit
791 uno::Sequence<sal_Int8> aNameBuffer(nPathLenToRead);
792 sal_Int32 nRead = aGrabber.readBytes(aNameBuffer, nPathLenToRead);
793 if (nRead < aNameBuffer.getLength())
794 aNameBuffer.realloc(nRead);
796 OUString sLOCPath = OUString::intern( reinterpret_cast<char *>(aNameBuffer.getArray()),
797 aNameBuffer.getLength(),
798 RTL_TEXTENCODING_UTF8 );
800 if ( rEntry.nPathLen == -1 ) // the file was created
802 rEntry.nPathLen = nPathLen;
803 rEntry.sPath = sLOCPath;
806 bBroken = rEntry.nPathLen != nPathLen
807 || rEntry.sPath != sLOCPath;
809 catch(...)
811 bBroken = true;
814 if ( bBroken && !bRecoveryMode )
815 throw ZipIOException("The stream seems to be broken!" );
817 return true;
820 sal_Int32 ZipFile::findEND()
822 // this method is called in constructor only, no need for mutex
823 sal_Int32 nLength, nPos, nEnd;
824 Sequence < sal_Int8 > aBuffer;
827 nLength = static_cast <sal_Int32 > (aGrabber.getLength());
828 if (nLength == 0 || nLength < ENDHDR)
829 return -1;
830 nPos = nLength - ENDHDR - ZIP_MAXNAMELEN;
831 nEnd = nPos >= 0 ? nPos : 0 ;
833 aGrabber.seek( nEnd );
835 auto nSize = nLength - nEnd;
836 if (nSize != aGrabber.readBytes(aBuffer, nSize))
837 throw ZipException("Zip END signature not found!" );
839 const sal_Int8 *pBuffer = aBuffer.getConstArray();
841 nPos = nSize - ENDHDR;
842 while ( nPos >= 0 )
844 if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 5 && pBuffer[nPos+3] == 6 )
845 return nPos + nEnd;
846 nPos--;
849 catch ( IllegalArgumentException& )
851 throw ZipException("Zip END signature not found!" );
853 catch ( NotConnectedException& )
855 throw ZipException("Zip END signature not found!" );
857 catch ( BufferSizeExceededException& )
859 throw ZipException("Zip END signature not found!" );
861 throw ZipException("Zip END signature not found!" );
864 sal_Int32 ZipFile::readCEN()
866 // this method is called in constructor only, no need for mutex
867 sal_Int32 nCenPos = -1, nEndPos, nLocPos;
868 sal_uInt16 nCount;
872 nEndPos = findEND();
873 if (nEndPos == -1)
874 return -1;
875 aGrabber.seek(nEndPos + ENDTOT);
876 sal_uInt16 nTotal = aGrabber.ReadUInt16();
877 sal_Int32 nCenLen = aGrabber.ReadInt32();
878 sal_Int32 nCenOff = aGrabber.ReadInt32();
880 if ( nTotal * CENHDR > nCenLen )
881 throw ZipException("invalid END header (bad entry count)" );
883 if ( nTotal > ZIP_MAXENTRIES )
884 throw ZipException("too many entries in ZIP File" );
886 if ( nCenLen < 0 || nCenLen > nEndPos )
887 throw ZipException("Invalid END header (bad central directory size)" );
889 nCenPos = nEndPos - nCenLen;
891 if ( nCenOff < 0 || nCenOff > nCenPos )
892 throw ZipException("Invalid END header (bad central directory size)" );
894 nLocPos = nCenPos - nCenOff;
895 aGrabber.seek( nCenPos );
896 Sequence < sal_Int8 > aCENBuffer ( nCenLen );
897 sal_Int64 nRead = aGrabber.readBytes ( aCENBuffer, nCenLen );
898 if ( static_cast < sal_Int64 > ( nCenLen ) != nRead )
899 throw ZipException ("Error reading CEN into memory buffer!" );
901 MemoryByteGrabber aMemGrabber(aCENBuffer);
903 ZipEntry aEntry;
904 sal_Int16 nCommentLen;
906 for (nCount = 0 ; nCount < nTotal; nCount++)
908 sal_Int32 nTestSig = aMemGrabber.ReadInt32();
909 if ( nTestSig != CENSIG )
910 throw ZipException("Invalid CEN header (bad signature)" );
912 aMemGrabber.skipBytes ( 2 );
913 aEntry.nVersion = aMemGrabber.ReadInt16();
915 if ( ( aEntry.nVersion & 1 ) == 1 )
916 throw ZipException("Invalid CEN header (encrypted entry)" );
918 aEntry.nFlag = aMemGrabber.ReadInt16();
919 aEntry.nMethod = aMemGrabber.ReadInt16();
921 if ( aEntry.nMethod != STORED && aEntry.nMethod != DEFLATED)
922 throw ZipException("Invalid CEN header (bad compression method)" );
924 aEntry.nTime = aMemGrabber.ReadInt32();
925 aEntry.nCrc = aMemGrabber.ReadInt32();
927 sal_uInt32 nCompressedSize = aMemGrabber.ReadUInt32();
928 sal_uInt32 nSize = aMemGrabber.ReadUInt32();
929 aEntry.nPathLen = aMemGrabber.ReadInt16();
930 aEntry.nExtraLen = aMemGrabber.ReadInt16();
931 nCommentLen = aMemGrabber.ReadInt16();
932 aMemGrabber.skipBytes ( 8 );
933 sal_uInt32 nOffset = aMemGrabber.ReadUInt32();
935 // FIXME64: need to read the 64bit header instead
936 if ( nSize == 0xffffffff ||
937 nOffset == 0xffffffff ||
938 nCompressedSize == 0xffffffff ) {
939 throw ZipException("PK64 zip file entry" );
941 aEntry.nCompressedSize = nCompressedSize;
942 aEntry.nSize = nSize;
943 aEntry.nOffset = nOffset;
945 aEntry.nOffset += nLocPos;
946 aEntry.nOffset *= -1;
948 if ( aEntry.nPathLen < 0 )
949 throw ZipException("unexpected name length" );
951 if ( nCommentLen < 0 )
952 throw ZipException("unexpected comment length" );
954 if ( aEntry.nExtraLen < 0 )
955 throw ZipException("unexpected extra header info length" );
957 if (aEntry.nPathLen > aMemGrabber.remainingSize())
958 throw ZipException("name too long");
960 // read always in UTF8, some tools seem not to set UTF8 bit
961 aEntry.sPath = OUString::intern ( reinterpret_cast<char const *>(aMemGrabber.getCurrentPos()),
962 aEntry.nPathLen,
963 RTL_TEXTENCODING_UTF8 );
965 if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aEntry.sPath, true ) )
966 throw ZipException("Zip entry has an invalid name." );
968 aMemGrabber.skipBytes( aEntry.nPathLen + aEntry.nExtraLen + nCommentLen );
969 aEntries[aEntry.sPath] = aEntry;
972 if (nCount != nTotal)
973 throw ZipException("Count != Total" );
975 catch ( IllegalArgumentException & )
977 // seek can throw this...
978 nCenPos = -1; // make sure we return -1 to indicate an error
980 return nCenPos;
983 void ZipFile::recover()
985 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
987 sal_Int64 nLength;
988 Sequence < sal_Int8 > aBuffer;
992 nLength = aGrabber.getLength();
993 if (nLength == 0 || nLength < ENDHDR)
994 return;
996 aGrabber.seek( 0 );
998 const sal_Int64 nToRead = 32000;
999 for( sal_Int64 nGenPos = 0; aGrabber.readBytes( aBuffer, nToRead ) && aBuffer.getLength() > 16; )
1001 const sal_Int8 *pBuffer = aBuffer.getConstArray();
1002 sal_Int32 nBufSize = aBuffer.getLength();
1004 sal_Int64 nPos = 0;
1005 // the buffer should contain at least one header,
1006 // or if it is end of the file, at least the postheader with sizes and hash
1007 while( nPos < nBufSize - 30
1008 || ( nBufSize < nToRead && nPos < nBufSize - 16 ) )
1011 if ( nPos < nBufSize - 30 && pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 3 && pBuffer[nPos+3] == 4 )
1013 ZipEntry aEntry;
1014 Sequence<sal_Int8> aTmpBuffer(&(pBuffer[nPos+4]), 26);
1015 MemoryByteGrabber aMemGrabber(aTmpBuffer);
1017 aEntry.nVersion = aMemGrabber.ReadInt16();
1018 if ( ( aEntry.nVersion & 1 ) != 1 )
1020 aEntry.nFlag = aMemGrabber.ReadInt16();
1021 aEntry.nMethod = aMemGrabber.ReadInt16();
1023 if ( aEntry.nMethod == STORED || aEntry.nMethod == DEFLATED )
1025 aEntry.nTime = aMemGrabber.ReadInt32();
1026 aEntry.nCrc = aMemGrabber.ReadInt32();
1027 sal_uInt32 nCompressedSize = aMemGrabber.ReadUInt32();
1028 sal_uInt32 nSize = aMemGrabber.ReadUInt32();
1029 aEntry.nPathLen = aMemGrabber.ReadInt16();
1030 aEntry.nExtraLen = aMemGrabber.ReadInt16();
1032 // FIXME64: need to read the 64bit header instead
1033 if ( nSize == 0xffffffff ||
1034 nCompressedSize == 0xffffffff ) {
1035 throw ZipException("PK64 zip file entry" );
1037 aEntry.nCompressedSize = nCompressedSize;
1038 aEntry.nSize = nSize;
1040 sal_Int32 nDescrLength =
1041 ( aEntry.nMethod == DEFLATED && ( aEntry.nFlag & 8 ) ) ? 16 : 0;
1043 sal_Int64 nDataSize = ( aEntry.nMethod == DEFLATED ) ? aEntry.nCompressedSize : aEntry.nSize;
1044 sal_Int64 nBlockLength = nDataSize + aEntry.nPathLen + aEntry.nExtraLen + 30 + nDescrLength;
1045 if ( aEntry.nPathLen >= 0 && aEntry.nExtraLen >= 0
1046 && ( nGenPos + nPos + nBlockLength ) <= nLength )
1048 // read always in UTF8, some tools seem not to set UTF8 bit
1049 if( nPos + 30 + aEntry.nPathLen <= nBufSize )
1050 aEntry.sPath = OUString ( reinterpret_cast<char const *>(&pBuffer[nPos + 30]),
1051 aEntry.nPathLen,
1052 RTL_TEXTENCODING_UTF8 );
1053 else
1055 Sequence < sal_Int8 > aFileName;
1056 aGrabber.seek( nGenPos + nPos + 30 );
1057 aGrabber.readBytes( aFileName, aEntry.nPathLen );
1058 aEntry.sPath = OUString ( reinterpret_cast<char *>(aFileName.getArray()),
1059 aFileName.getLength(),
1060 RTL_TEXTENCODING_UTF8 );
1061 aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength());
1064 aEntry.nOffset = nGenPos + nPos + 30 + aEntry.nPathLen + aEntry.nExtraLen;
1066 if ( ( aEntry.nSize || aEntry.nCompressedSize ) && !checkSizeAndCRC( aEntry ) )
1068 aEntry.nCrc = 0;
1069 aEntry.nCompressedSize = 0;
1070 aEntry.nSize = 0;
1073 if ( aEntries.find( aEntry.sPath ) == aEntries.end() )
1074 aEntries[aEntry.sPath] = aEntry;
1079 nPos += 4;
1081 else if (pBuffer[nPos] == 'P' && pBuffer[nPos+1] == 'K' && pBuffer[nPos+2] == 7 && pBuffer[nPos+3] == 8 )
1083 sal_Int64 nCompressedSize, nSize;
1084 Sequence<sal_Int8> aTmpBuffer(&(pBuffer[nPos+4]), 12);
1085 MemoryByteGrabber aMemGrabber(aTmpBuffer);
1086 sal_Int32 nCRC32 = aMemGrabber.ReadInt32();
1087 sal_uInt32 nCompressedSize32 = aMemGrabber.ReadUInt32();
1088 sal_uInt32 nSize32 = aMemGrabber.ReadUInt32();
1090 // FIXME64: work to be done here ...
1091 nCompressedSize = nCompressedSize32;
1092 nSize = nSize32;
1094 for( EntryHash::iterator aIter = aEntries.begin(); aIter != aEntries.end(); ++aIter )
1096 ZipEntry aTmp = (*aIter).second;
1098 // this is a broken package, accept this block not only for DEFLATED streams
1099 if( (*aIter).second.nFlag & 8 )
1101 sal_Int64 nStreamOffset = nGenPos + nPos - nCompressedSize;
1102 if ( nStreamOffset == (*aIter).second.nOffset && nCompressedSize > (*aIter).second.nCompressedSize )
1104 // only DEFLATED blocks need to be checked
1105 bool bAcceptBlock = ( (*aIter).second.nMethod == STORED && nCompressedSize == nSize );
1107 if ( !bAcceptBlock )
1109 sal_Int64 nRealSize = 0;
1110 sal_Int32 nRealCRC = 0;
1111 getSizeAndCRC( nStreamOffset, nCompressedSize, &nRealSize, &nRealCRC );
1112 bAcceptBlock = ( nRealSize == nSize && nRealCRC == nCRC32 );
1115 if ( bAcceptBlock )
1117 (*aIter).second.nCrc = nCRC32;
1118 (*aIter).second.nCompressedSize = nCompressedSize;
1119 (*aIter).second.nSize = nSize;
1122 #if 0
1123 // for now ignore clearly broken streams
1124 else if( !(*aIter).second.nCompressedSize )
1126 (*aIter).second.nCrc = nCRC32;
1127 sal_Int32 nRealStreamSize = nGenPos + nPos - (*aIter).second.nOffset;
1128 (*aIter).second.nCompressedSize = nGenPos + nPos - (*aIter).second.nOffset;
1129 (*aIter).second.nSize = nSize;
1131 #endif
1135 nPos += 4;
1137 else
1138 nPos++;
1141 nGenPos += nPos;
1142 aGrabber.seek( nGenPos );
1145 catch ( IllegalArgumentException& )
1147 throw ZipException("Zip END signature not found!" );
1149 catch ( NotConnectedException& )
1151 throw ZipException("Zip END signature not found!" );
1153 catch ( BufferSizeExceededException& )
1155 throw ZipException("Zip END signature not found!" );
1159 bool ZipFile::checkSizeAndCRC( const ZipEntry& aEntry )
1161 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1163 sal_Int32 nCRC = 0;
1164 sal_Int64 nSize = 0;
1166 if( aEntry.nMethod == STORED )
1167 return ( getCRC( aEntry.nOffset, aEntry.nSize ) == aEntry.nCrc );
1169 getSizeAndCRC( aEntry.nOffset, aEntry.nCompressedSize, &nSize, &nCRC );
1170 return ( aEntry.nSize == nSize && aEntry.nCrc == nCRC );
1173 sal_Int32 ZipFile::getCRC( sal_Int64 nOffset, sal_Int64 nSize )
1175 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1177 Sequence < sal_Int8 > aBuffer;
1178 CRC32 aCRC;
1179 sal_Int64 nBlockSize = ::std::min(nSize, static_cast< sal_Int64 >(32000));
1181 aGrabber.seek( nOffset );
1182 for (sal_Int64 ind = 0;
1183 aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nSize;
1184 ++ind)
1186 sal_Int64 nLen = ::std::min(nBlockSize, nSize - ind * nBlockSize);
1187 aCRC.updateSegment(aBuffer, static_cast<sal_Int32>(nLen));
1190 return aCRC.getValue();
1193 void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_Int64 *nSize, sal_Int32 *nCRC )
1195 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1197 Sequence < sal_Int8 > aBuffer;
1198 CRC32 aCRC;
1199 sal_Int64 nRealSize = 0;
1200 Inflater aInflaterLocal( true );
1201 sal_Int32 nBlockSize = static_cast< sal_Int32 > (::std::min( nCompressedSize, static_cast< sal_Int64 >( 32000 ) ) );
1203 aGrabber.seek( nOffset );
1204 for ( sal_Int64 ind = 0;
1205 !aInflaterLocal.finished() && aGrabber.readBytes( aBuffer, nBlockSize ) && ind * nBlockSize < nCompressedSize;
1206 ind++ )
1208 Sequence < sal_Int8 > aData( nBlockSize );
1209 sal_Int32 nLastInflated = 0;
1210 sal_Int64 nInBlock = 0;
1212 aInflaterLocal.setInput( aBuffer );
1215 nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize );
1216 aCRC.updateSegment( aData, nLastInflated );
1217 nInBlock += nLastInflated;
1218 } while( !aInflater.finished() && nLastInflated );
1220 nRealSize += nInBlock;
1223 *nSize = nRealSize;
1224 *nCRC = aCRC.getValue();
1227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */