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