1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
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
69 #define THROW_WHERE ""
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
,
78 : m_aMutexHolder( aMutexHolder
)
82 , m_xContext ( rxContext
)
83 , bRecoveryMode( false )
87 if ( readCEN() == -1 )
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
)
103 , m_xContext ( rxContext
)
104 , bRecoveryMode( bForceRecovery
)
108 if ( bForceRecovery
)
112 else if ( readCEN() == -1 )
115 throw ZipException("stream data looks to be broken" );
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
);
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
);
205 throw ZipIOException("Unknown cipher algorithm is requested!" );
211 void ZipFile::StaticFillHeader( const ::rtl::Reference
< EncryptionData
>& rData
,
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
) );
223 *(pHeader
++) = ( n_ConstHeader
>> 0 ) & 0xFF;
224 *(pHeader
++) = ( n_ConstHeader
>> 8 ) & 0xFF;
225 *(pHeader
++) = ( n_ConstHeader
>> 16 ) & 0xFF;
226 *(pHeader
++) = ( n_ConstHeader
>> 24 ) & 0xFF;
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
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
,
309 sal_Int32
&rChecksumAlg
,
310 sal_Int32
&rDerivedKeySize
,
311 sal_Int32
&rStartKeyGenID
,
313 OUString
& aMediaType
,
314 const uno::Reference
< XInputStream
>& rStream
)
317 const sal_Int32 nHeaderSize
= n_ConstHeaderSize
- 4;
318 Sequence
< sal_Int8
> aBuffer ( nHeaderSize
);
319 if ( nHeaderSize
== rStream
->readBytes ( aBuffer
, nHeaderSize
) )
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
) );
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
)
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
);
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;
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
);
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!" );
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() )
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
503 bool ZipFile::hasValidPassword ( ZipEntry
const & rEntry
, const ::rtl::Reference
< EncryptionData
>& rData
)
505 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
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
);
530 class XBufferedStream
: public cppu::WeakImplHelper
<css::io::XInputStream
>
532 std::vector
<sal_Int8
> maBytes
;
535 size_t remainingSize() const
537 return maBytes
.size() - mnPos
;
540 bool hasBytes() const
542 return mnPos
< maBytes
.size();
546 XBufferedStream( const uno::Reference
<XInputStream
>& xSrcStream
) : mnPos(0)
548 const sal_Int32 nBufSize
= 8192;
550 sal_Int32 nRemaining
= xSrcStream
->available();
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
));
564 while (nRemaining
> nBufSize
)
566 const auto nBytes
= readAndCopy(nBufSize
);
570 nRemaining
-= nBytes
;
574 nRead
+= readAndCopy(nRemaining
);
575 maBytes
.resize(nRead
);
578 virtual sal_Int32 SAL_CALL
readBytes( uno::Sequence
<sal_Int8
>& rData
, sal_Int32 nBytesToRead
) override
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
)
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
605 mnPos
+= nBytesToSkip
;
608 virtual sal_Int32 SAL_CALL
available() override
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
,
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());
646 xBufStream
= new XBufferedStream(xSrcStream
.get());
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
,
659 const rtl::Reference
<comphelper::RefCountedMutex
>& aMutexHolder
)
661 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
663 if ( rEntry
.nOffset
<= 0 )
666 // We want to return a rawStream if we either don't have a key or if the
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
,
679 bNeedRawStream
? UNBUFF_STREAM_RAW
: UNBUFF_STREAM_DATA
,
683 uno::Reference
< XInputStream
> ZipFile::getDataStream( ZipEntry
& rEntry
,
684 const ::rtl::Reference
< EncryptionData
> &rData
,
686 const rtl::Reference
<comphelper::RefCountedMutex
>& aMutexHolder
)
688 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
690 if ( rEntry
.nOffset
<= 0 )
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;
698 // in case no digest is provided there is no way
699 // to detect password correctness
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
);
710 bNeedRawStream
= ( rEntry
.nMethod
== STORED
);
712 return createStreamForZipEntry ( aMutexHolder
,
715 bNeedRawStream
? UNBUFF_STREAM_RAW
: UNBUFF_STREAM_DATA
,
719 uno::Reference
< XInputStream
> ZipFile::getRawData( ZipEntry
& rEntry
,
720 const ::rtl::Reference
< EncryptionData
>& rData
,
722 const rtl::Reference
<comphelper::RefCountedMutex
>& aMutexHolder
,
723 const bool bUseBufferedStream
)
725 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
727 if ( rEntry
.nOffset
<= 0 )
730 return createStreamForZipEntry ( aMutexHolder
, rEntry
, rData
, UNBUFF_STREAM_RAW
, bIsEncrypted
, bUseBufferedStream
);
733 uno::Reference
< XInputStream
> ZipFile::getWrappedRawStream(
735 const ::rtl::Reference
< EncryptionData
>& rData
,
736 const OUString
& aMediaType
,
737 const rtl::Reference
<comphelper::RefCountedMutex
>& aMutexHolder
)
739 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
742 throw packages::NoEncryptionException(THROW_WHERE
);
744 if ( rEntry
.nOffset
<= 0 )
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
;
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)
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
;
814 if ( bBroken
&& !bRecoveryMode
)
815 throw ZipIOException("The stream seems to be broken!" );
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
)
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
;
844 if (pBuffer
[nPos
] == 'P' && pBuffer
[nPos
+1] == 'K' && pBuffer
[nPos
+2] == 5 && pBuffer
[nPos
+3] == 6 )
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
;
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
);
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()),
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
983 void ZipFile::recover()
985 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
988 Sequence
< sal_Int8
> aBuffer
;
992 nLength
= aGrabber
.getLength();
993 if (nLength
== 0 || nLength
< ENDHDR
)
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();
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 )
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]),
1052 RTL_TEXTENCODING_UTF8
);
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
) )
1069 aEntry
.nCompressedSize
= 0;
1073 if ( aEntries
.find( aEntry
.sPath
) == aEntries
.end() )
1074 aEntries
[aEntry
.sPath
] = aEntry
;
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
;
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
);
1117 (*aIter
).second
.nCrc
= nCRC32
;
1118 (*aIter
).second
.nCompressedSize
= nCompressedSize
;
1119 (*aIter
).second
.nSize
= nSize
;
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
;
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() );
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
;
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
;
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
;
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
;
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
;
1224 *nCRC
= aCRC
.getValue();
1227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */