xref: /AOO41X/main/package/source/zipapi/XUnbufferedStream.cxx (revision a38728232e8c39f9058a1a2aa8ee4e6db7b8ca34)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 
27 #include <com/sun/star/packages/zip/ZipConstants.hpp>
28 #include <com/sun/star/packages/zip/ZipIOException.hpp>
29 #include <com/sun/star/xml/crypto/CipherID.hpp>
30 
31 #include <XUnbufferedStream.hxx>
32 #include <EncryptionData.hxx>
33 #include <PackageConstants.hxx>
34 #include <ZipFile.hxx>
35 #include <EncryptedDataHeader.hxx>
36 #include <algorithm>
37 #include <string.h>
38 
39 #include <osl/mutex.hxx>
40 
41 #if 0
42 // for debugging purposes here
43 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
44 #include <comphelper/processfactory.hxx>
45 using namespace ::com::sun::star;
46 #endif
47 
48 using namespace ::com::sun::star;
49 using namespace com::sun::star::packages::zip::ZipConstants;
50 using namespace com::sun::star::io;
51 using namespace com::sun::star::uno;
52 using com::sun::star::lang::IllegalArgumentException;
53 using com::sun::star::packages::zip::ZipIOException;
54 using ::rtl::OUString;
55 
XUnbufferedStream(const uno::Reference<lang::XMultiServiceFactory> & xFactory,SotMutexHolderRef aMutexHolder,ZipEntry & rEntry,Reference<XInputStream> xNewZipStream,const::rtl::Reference<EncryptionData> & rData,sal_Int8 nStreamMode,sal_Bool bIsEncrypted,const::rtl::OUString & aMediaType,sal_Bool bRecoveryMode)56 XUnbufferedStream::XUnbufferedStream(
57                       const uno::Reference< lang::XMultiServiceFactory >& xFactory,
58                       SotMutexHolderRef aMutexHolder,
59                       ZipEntry & rEntry,
60                       Reference < XInputStream > xNewZipStream,
61                       const ::rtl::Reference< EncryptionData >& rData,
62                       sal_Int8 nStreamMode,
63                       sal_Bool bIsEncrypted,
64                       const ::rtl::OUString& aMediaType,
65                       sal_Bool bRecoveryMode )
66 : maMutexHolder( aMutexHolder.Is() ? aMutexHolder : SotMutexHolderRef( new SotMutexHolder ) )
67 , mxZipStream ( xNewZipStream )
68 , mxZipSeek ( xNewZipStream, UNO_QUERY )
69 , maEntry ( rEntry )
70 , mxData ( rData )
71 , mnBlockSize( 1 )
72 , maInflater ( sal_True )
73 , mbRawStream ( nStreamMode == UNBUFF_STREAM_RAW || nStreamMode == UNBUFF_STREAM_WRAPPEDRAW )
74 , mbWrappedRaw ( nStreamMode == UNBUFF_STREAM_WRAPPEDRAW )
75 , mbFinished ( sal_False )
76 , mnHeaderToRead ( 0 )
77 , mnZipCurrent ( 0 )
78 , mnZipEnd ( 0 )
79 , mnZipSize ( 0 )
80 , mnMyCurrent ( 0 )
81 , mbCheckCRC( !bRecoveryMode )
82 {
83     mnZipCurrent = maEntry.nOffset;
84     if ( mbRawStream )
85     {
86         mnZipSize = maEntry.nMethod == DEFLATED ? maEntry.nCompressedSize : maEntry.nSize;
87         mnZipEnd = maEntry.nOffset + mnZipSize;
88     }
89     else
90     {
91         mnZipSize = maEntry.nSize;
92         mnZipEnd = maEntry.nMethod == DEFLATED ? maEntry.nOffset + maEntry.nCompressedSize : maEntry.nOffset + maEntry.nSize;
93     }
94     sal_Bool bHaveEncryptData = ( rData.is() && rData->m_aSalt.getLength() && rData->m_aInitVector.getLength() && rData->m_nIterationCount != 0 ) ? sal_True : sal_False;
95     sal_Bool bMustDecrypt = ( nStreamMode == UNBUFF_STREAM_DATA && bHaveEncryptData && bIsEncrypted ) ? sal_True : sal_False;
96 
97     if ( bMustDecrypt )
98     {
99         m_xCipherContext = ZipFile::StaticGetCipher( xFactory, rData, false );
100         mnBlockSize = ( rData->m_nEncAlg == xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 1 );
101     }
102 
103     if ( bHaveEncryptData && mbWrappedRaw && bIsEncrypted )
104     {
105         // if we have the data needed to decrypt it, but didn't want it decrypted (or
106         // we couldn't decrypt it due to wrong password), then we prepend this
107         // data to the stream
108 
109         // Make a buffer big enough to hold both the header and the data itself
110         maHeader.realloc  ( n_ConstHeaderSize +
111                             rData->m_aInitVector.getLength() +
112                             rData->m_aSalt.getLength() +
113                             rData->m_aDigest.getLength() +
114                             aMediaType.getLength() * sizeof( sal_Unicode ) );
115         sal_Int8 * pHeader = maHeader.getArray();
116         ZipFile::StaticFillHeader( rData, rEntry.nSize, aMediaType, pHeader );
117         mnHeaderToRead = static_cast < sal_Int16 > ( maHeader.getLength() );
118     }
119 }
120 
121 // allows to read package raw stream
XUnbufferedStream(const uno::Reference<lang::XMultiServiceFactory> &,const Reference<XInputStream> & xRawStream,const::rtl::Reference<EncryptionData> & rData)122 XUnbufferedStream::XUnbufferedStream(
123                     const uno::Reference< lang::XMultiServiceFactory >& /*xFactory*/,
124                     const Reference < XInputStream >& xRawStream,
125                     const ::rtl::Reference< EncryptionData >& rData )
126 : maMutexHolder( new SotMutexHolder )
127 , mxZipStream ( xRawStream )
128 , mxZipSeek ( xRawStream, UNO_QUERY )
129 , mxData ( rData )
130 , mnBlockSize( 1 )
131 , maInflater ( sal_True )
132 , mbRawStream ( sal_False )
133 , mbWrappedRaw ( sal_False )
134 , mbFinished ( sal_False )
135 , mnHeaderToRead ( 0 )
136 , mnZipCurrent ( 0 )
137 , mnZipEnd ( 0 )
138 , mnZipSize ( 0 )
139 , mnMyCurrent ( 0 )
140 , mbCheckCRC( sal_False )
141 {
142     // for this scenario maEntry is not set !!!
143     OSL_ENSURE( mxZipSeek.is(), "The stream must be seekable!\n" );
144 
145     // skip raw header, it must be already parsed to rData
146     mnZipCurrent = n_ConstHeaderSize + rData->m_aInitVector.getLength() +
147                             rData->m_aSalt.getLength() + rData->m_aDigest.getLength();
148 
149     try {
150         if ( mxZipSeek.is() )
151             mnZipSize = mxZipSeek->getLength();
152     } catch( Exception& )
153     {
154         // in case of problem the size will stay set to 0
155     }
156 
157     mnZipEnd = mnZipCurrent + mnZipSize;
158 
159     // the raw data will not be decrypted, no need for the cipher
160     // m_xCipherContext = ZipFile::StaticGetCipher( xFactory, rData, false );
161 }
162 
~XUnbufferedStream()163 XUnbufferedStream::~XUnbufferedStream()
164 {
165 }
166 
readBytes(Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)167 sal_Int32 SAL_CALL XUnbufferedStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
168         throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
169 {
170     ::osl::MutexGuard aGuard( maMutexHolder->GetMutex() );
171 
172     sal_Int32 nRequestedBytes = nBytesToRead;
173     OSL_ENSURE( !mnHeaderToRead || mbWrappedRaw, "Only encrypted raw stream can be provided with header!" );
174     if ( mnMyCurrent + nRequestedBytes > mnZipSize + maHeader.getLength() )
175         nRequestedBytes = static_cast < sal_Int32 > ( mnZipSize + maHeader.getLength() - mnMyCurrent );
176 
177     sal_Int32 nRead = 0, nLastRead = 0, nTotal = 0;
178     aData.realloc ( nRequestedBytes );
179     if ( nRequestedBytes )
180     {
181         if ( mbRawStream )
182         {
183             sal_Int64 nDiff = mnZipEnd - mnZipCurrent;
184 
185             if ( mbWrappedRaw && mnHeaderToRead )
186             {
187                 sal_Int16 nHeadRead = static_cast< sal_Int16 >(( nRequestedBytes > mnHeaderToRead ?
188                                                                                  mnHeaderToRead : nRequestedBytes ));
189                 rtl_copyMemory ( aData.getArray(), maHeader.getConstArray() + maHeader.getLength() - mnHeaderToRead, nHeadRead );
190                 mnHeaderToRead = mnHeaderToRead - nHeadRead;
191 
192                 if ( nHeadRead < nRequestedBytes )
193                 {
194                     sal_Int32 nToRead = nRequestedBytes - nHeadRead;
195                     nToRead = ( nDiff < nToRead ) ? sal::static_int_cast< sal_Int32 >( nDiff ) : nToRead;
196 
197                     Sequence< sal_Int8 > aPureData( nToRead );
198                     mxZipSeek->seek ( mnZipCurrent );
199                     nRead = mxZipStream->readBytes ( aPureData, nToRead );
200                     mnZipCurrent += nRead;
201 
202                     aPureData.realloc( nRead );
203                     if ( mbCheckCRC )
204                         maCRC.update( aPureData );
205 
206                     aData.realloc( nHeadRead + nRead );
207 
208                     sal_Int8* pPureBuffer = aPureData.getArray();
209                     sal_Int8* pBuffer = aData.getArray();
210                     for ( sal_Int32 nInd = 0; nInd < nRead; nInd++ )
211                         pBuffer[ nHeadRead + nInd ] = pPureBuffer[ nInd ];
212                 }
213 
214                 nRead += nHeadRead;
215             }
216             else
217             {
218                 mxZipSeek->seek ( mnZipCurrent );
219 
220                 nRead = mxZipStream->readBytes (
221                                         aData,
222                                         static_cast < sal_Int32 > ( nDiff < nRequestedBytes ? nDiff : nRequestedBytes ) );
223 
224                 mnZipCurrent += nRead;
225 
226                 aData.realloc( nRead );
227                 if ( mbWrappedRaw && mbCheckCRC )
228                     maCRC.update( aData );
229             }
230         }
231         else
232         {
233             while ( 0 == ( nLastRead = maInflater.doInflateSegment( aData, nRead, aData.getLength() - nRead ) ) ||
234                   ( nRead + nLastRead != nRequestedBytes && mnZipCurrent < mnZipEnd ) )
235             {
236                 nRead += nLastRead;
237 
238                 if ( nRead > nRequestedBytes )
239                     throw RuntimeException(
240                         OUString( RTL_CONSTASCII_USTRINGPARAM( "Should not be possible to read more then requested!" ) ),
241                         Reference< XInterface >() );
242 
243                 if ( maInflater.finished() || maInflater.getLastInflateError() )
244                     throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ),
245                                         Reference< XInterface >() );
246 
247                 if ( maInflater.needsDictionary() )
248                     throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "Dictionaries are not supported!" ) ),
249                                         Reference< XInterface >() );
250 
251                 sal_Int32 nDiff = static_cast< sal_Int32 >( mnZipEnd - mnZipCurrent );
252                 if ( nDiff > 0 )
253                 {
254                     mxZipSeek->seek ( mnZipCurrent );
255 
256                     sal_Int32 nToRead = std::max( nRequestedBytes, static_cast< sal_Int32 >( 8192 ) );
257                     if ( mnBlockSize > 1 )
258                         nToRead = nToRead + mnBlockSize - nToRead % mnBlockSize;
259                     nToRead = std::min( nDiff, nToRead );
260 
261                     sal_Int32 nZipRead = mxZipStream->readBytes( maCompBuffer, nToRead );
262                     if ( nZipRead < nToRead )
263                         throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "No expected data!" ) ),
264                                             Reference< XInterface >() );
265 
266                     mnZipCurrent += nZipRead;
267                     // maCompBuffer now has the data, check if we need to decrypt
268                     // before passing to the Inflater
269                     if ( m_xCipherContext.is() )
270                     {
271                         if ( mbCheckCRC )
272                             maCRC.update( maCompBuffer );
273 
274                         maCompBuffer = m_xCipherContext->convertWithCipherContext( maCompBuffer );
275                         if ( mnZipCurrent == mnZipEnd )
276                         {
277                             uno::Sequence< sal_Int8 > aSuffix = m_xCipherContext->finalizeCipherContextAndDispose();
278                             if ( aSuffix.getLength() )
279                             {
280                                 sal_Int32 nOldLen = maCompBuffer.getLength();
281                                 maCompBuffer.realloc( nOldLen + aSuffix.getLength() );
282                                 rtl_copyMemory( maCompBuffer.getArray() + nOldLen, aSuffix.getConstArray(), aSuffix.getLength() );
283                             }
284                         }
285                     }
286                     maInflater.setInput ( maCompBuffer );
287                 }
288                 else
289                 {
290                     throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ),
291                                         Reference< XInterface >() );
292                 }
293             }
294         }
295 
296         mnMyCurrent += nRead + nLastRead;
297         nTotal = nRead + nLastRead;
298         if ( nTotal < nRequestedBytes)
299             aData.realloc ( nTotal );
300 
301         if ( mbCheckCRC && ( !mbRawStream || mbWrappedRaw ) )
302         {
303             if ( !m_xCipherContext.is() && !mbWrappedRaw )
304                 maCRC.update( aData );
305 
306 #if 0
307             // for debugging purposes here
308             if ( mbWrappedRaw )
309             {
310                 if ( 0 )
311                 {
312                     uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
313                     uno::Reference< ucb::XSimpleFileAccess > xAccess( xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY );
314                     uno::Reference< io::XOutputStream > xOut = xAccess->openFileWrite( ::rtl::OUString::createFromAscii( "file:///d:/777/Encrypted/picture" ) );
315                     xOut->writeBytes( aData );
316                     xOut->closeOutput();
317                 }
318             }
319 #endif
320 
321             if ( mnZipSize + maHeader.getLength() == mnMyCurrent && maCRC.getValue() != maEntry.nCrc )
322                 throw ZipIOException( OUString( RTL_CONSTASCII_USTRINGPARAM( "The stream seems to be broken!" ) ),
323                                     Reference< XInterface >() );
324         }
325     }
326 
327     return nTotal;
328 }
329 
readSomeBytes(Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)330 sal_Int32 SAL_CALL XUnbufferedStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
331         throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
332 {
333     return readBytes ( aData, nMaxBytesToRead );
334 }
skipBytes(sal_Int32 nBytesToSkip)335 void SAL_CALL XUnbufferedStream::skipBytes( sal_Int32 nBytesToSkip )
336         throw( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
337 {
338     if ( nBytesToSkip )
339     {
340         Sequence < sal_Int8 > aSequence ( nBytesToSkip );
341         readBytes ( aSequence, nBytesToSkip );
342     }
343 }
344 
available()345 sal_Int32 SAL_CALL XUnbufferedStream::available(  )
346         throw( NotConnectedException, IOException, RuntimeException)
347 {
348     return static_cast < sal_Int32 > ( mnZipSize - mnMyCurrent );
349 }
350 
closeInput()351 void SAL_CALL XUnbufferedStream::closeInput(  )
352         throw( NotConnectedException, IOException, RuntimeException)
353 {
354 }
355 /*
356 void SAL_CALL XUnbufferedStream::seek( sal_Int64 location )
357         throw( IllegalArgumentException, IOException, RuntimeException)
358 {
359 }
360 sal_Int64 SAL_CALL XUnbufferedStream::getPosition(  )
361         throw(IOException, RuntimeException)
362 {
363     return mnMyCurrent;
364 }
365 sal_Int64 SAL_CALL XUnbufferedStream::getLength(  )
366         throw(IOException, RuntimeException)
367 {
368     return mnZipSize;
369 }
370 */
371