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