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 #include "oox/helper/binaryinputstream.hxx"
25 
26 #include <com/sun/star/io/XInputStream.hpp>
27 #include <com/sun/star/io/XSeekable.hpp>
28 #include <string.h>
29 #include <vector>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include "oox/helper/binaryoutputstream.hxx"
33 
34 namespace oox {
35 
36 // ============================================================================
37 
38 using namespace ::com::sun::star::io;
39 using namespace ::com::sun::star::uno;
40 
41 using ::rtl::OString;
42 using ::rtl::OStringBuffer;
43 using ::rtl::OStringToOUString;
44 using ::rtl::OUString;
45 using ::rtl::OUStringBuffer;
46 
47 namespace {
48 
49 const sal_Int32 INPUTSTREAM_BUFFERSIZE      = 0x8000;
50 
51 } // namespace
52 
53 // ============================================================================
54 
readNulCharArray()55 OString BinaryInputStream::readNulCharArray()
56 {
57     OStringBuffer aBuffer;
58     for( sal_uInt8 nChar = readuInt8(); !mbEof && (nChar > 0); readValue( nChar ) )
59         aBuffer.append( static_cast< sal_Char >( nChar ) );
60     return aBuffer.makeStringAndClear();
61 }
62 
readNulCharArrayUC(rtl_TextEncoding eTextEnc)63 OUString BinaryInputStream::readNulCharArrayUC( rtl_TextEncoding eTextEnc )
64 {
65     return OStringToOUString( readNulCharArray(), eTextEnc );
66 }
67 
readNulUnicodeArray()68 OUString BinaryInputStream::readNulUnicodeArray()
69 {
70     OUStringBuffer aBuffer;
71     for( sal_uInt16 nChar = readuInt16(); !mbEof && (nChar > 0); readValue( nChar ) )
72         aBuffer.append( static_cast< sal_Unicode >( nChar ) );
73     return aBuffer.makeStringAndClear();
74 }
75 
readCharArray(sal_Int32 nChars,bool bAllowNulChars)76 OString BinaryInputStream::readCharArray( sal_Int32 nChars, bool bAllowNulChars )
77 {
78     if( nChars <= 0 )
79         return OString();
80 
81     ::std::vector< sal_uInt8 > aBuffer;
82     sal_Int32 nCharsRead = readArray( aBuffer, nChars );
83     if( nCharsRead <= 0 )
84         return OString();
85 
86     aBuffer.resize( static_cast< size_t >( nCharsRead ) );
87     if( !bAllowNulChars )
88         ::std::replace( aBuffer.begin(), aBuffer.end(), '\0', '?' );
89 
90     return OString( reinterpret_cast< sal_Char* >( &aBuffer.front() ), nCharsRead );
91 }
92 
readCharArrayUC(sal_Int32 nChars,rtl_TextEncoding eTextEnc,bool bAllowNulChars)93 OUString BinaryInputStream::readCharArrayUC( sal_Int32 nChars, rtl_TextEncoding eTextEnc, bool bAllowNulChars )
94 {
95     return OStringToOUString( readCharArray( nChars, bAllowNulChars ), eTextEnc );
96 }
97 
readUnicodeArray(sal_Int32 nChars,bool bAllowNulChars)98 OUString BinaryInputStream::readUnicodeArray( sal_Int32 nChars, bool bAllowNulChars )
99 {
100     if( nChars <= 0 )
101         return OUString();
102 
103     ::std::vector< sal_uInt16 > aBuffer;
104     sal_Int32 nCharsRead = readArray( aBuffer, nChars );
105     if( nCharsRead <= 0 )
106         return OUString();
107 
108     aBuffer.resize( static_cast< size_t >( nCharsRead ) );
109     if( !bAllowNulChars )
110         ::std::replace( aBuffer.begin(), aBuffer.begin() + nCharsRead, '\0', '?' );
111 
112     OUStringBuffer aStringBuffer;
113     aStringBuffer.ensureCapacity( nCharsRead );
114     for( ::std::vector< sal_uInt16 >::iterator aIt = aBuffer.begin(), aEnd = aBuffer.end(); aIt != aEnd; ++aIt )
115         aStringBuffer.append( static_cast< sal_Unicode >( *aIt ) );
116     return aStringBuffer.makeStringAndClear();
117 }
118 
readCompressedUnicodeArray(sal_Int32 nChars,bool bCompressed,bool bAllowNulChars)119 OUString BinaryInputStream::readCompressedUnicodeArray( sal_Int32 nChars, bool bCompressed, bool bAllowNulChars )
120 {
121     return bCompressed ?
122          // ISO-8859-1 maps all byte values 0xHH to the same Unicode code point U+00HH
123         readCharArrayUC( nChars, RTL_TEXTENCODING_ISO_8859_1, bAllowNulChars ) :
124         readUnicodeArray( nChars, bAllowNulChars );
125 }
126 
copyToStream(BinaryOutputStream & rOutStrm,sal_Int64 nBytes,sal_Int32 nAtomSize)127 void BinaryInputStream::copyToStream( BinaryOutputStream& rOutStrm, sal_Int64 nBytes, sal_Int32 nAtomSize )
128 {
129     if( nBytes > 0 )
130     {
131         // make buffer size a multiple of the passed atom size
132         sal_Int32 nBufferSize = getLimitedValue< sal_Int32, sal_Int64 >( nBytes, 0, (INPUTSTREAM_BUFFERSIZE / nAtomSize) * nAtomSize );
133         StreamDataSequence aBuffer( nBufferSize );
134         while( nBytes > 0 )
135         {
136             sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int64 >( nBytes, 0, nBufferSize );
137             sal_Int32 nBytesRead = readData( aBuffer, nReadSize, nAtomSize );
138             rOutStrm.writeData( aBuffer );
139             if( nReadSize == nBytesRead )
140                 nBytes -= nReadSize;
141             else
142                 nBytes = 0;
143         }
144     }
145 }
146 
147 // ============================================================================
148 
BinaryXInputStream(const Reference<XInputStream> & rxInStrm,bool bAutoClose)149 BinaryXInputStream::BinaryXInputStream( const Reference< XInputStream >& rxInStrm, bool bAutoClose ) :
150     BinaryStreamBase( Reference< XSeekable >( rxInStrm, UNO_QUERY ).is() ),
151     BinaryXSeekableStream( Reference< XSeekable >( rxInStrm, UNO_QUERY ) ),
152     maBuffer( INPUTSTREAM_BUFFERSIZE ),
153     mxInStrm( rxInStrm ),
154     mbAutoClose( bAutoClose && rxInStrm.is() )
155 {
156     mbEof = !mxInStrm.is();
157 }
158 
~BinaryXInputStream()159 BinaryXInputStream::~BinaryXInputStream()
160 {
161     close();
162 }
163 
close()164 void BinaryXInputStream::close()
165 {
166     OSL_ENSURE( !mbAutoClose || mxInStrm.is(), "BinaryXInputStream::close - invalid call" );
167     if( mbAutoClose && mxInStrm.is() ) try
168     {
169         mxInStrm->closeInput();
170     }
171     catch( Exception& )
172     {
173         OSL_ENSURE( false, "BinaryXInputStream::close - closing input stream failed" );
174     }
175     mxInStrm.clear();
176     mbAutoClose = false;
177     BinaryXSeekableStream::close();
178 }
179 
readData(StreamDataSequence & orData,sal_Int32 nBytes,size_t)180 sal_Int32 BinaryXInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
181 {
182     sal_Int32 nRet = 0;
183     if( !mbEof && (nBytes > 0) ) try
184     {
185         nRet = mxInStrm->readBytes( orData, nBytes );
186         mbEof = nRet != nBytes;
187     }
188     catch( Exception& )
189     {
190         mbEof = true;
191     }
192     return nRet;
193 }
194 
readMemory(void * opMem,sal_Int32 nBytes,size_t nAtomSize)195 sal_Int32 BinaryXInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
196 {
197     sal_Int32 nRet = 0;
198     if( !mbEof && (nBytes > 0) )
199     {
200         sal_Int32 nBufferSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, INPUTSTREAM_BUFFERSIZE );
201         sal_uInt8* opnMem = reinterpret_cast< sal_uInt8* >( opMem );
202         while( !mbEof && (nBytes > 0) )
203         {
204             sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, nBufferSize );
205             sal_Int32 nBytesRead = readData( maBuffer, nReadSize, nAtomSize );
206             if( nBytesRead > 0 )
207                 memcpy( opnMem, maBuffer.getConstArray(), static_cast< size_t >( nBytesRead ) );
208             opnMem += nBytesRead;
209             nBytes -= nBytesRead;
210             nRet += nBytesRead;
211         }
212     }
213     return nRet;
214 }
215 
skip(sal_Int32 nBytes,size_t)216 void BinaryXInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
217 {
218     if( !mbEof ) try
219     {
220         mxInStrm->skipBytes( nBytes );
221     }
222     catch( Exception& )
223     {
224         mbEof = true;
225     }
226 }
227 
228 // ============================================================================
229 
SequenceInputStream(const StreamDataSequence & rData)230 SequenceInputStream::SequenceInputStream( const StreamDataSequence& rData ) :
231     BinaryStreamBase( true ),
232     SequenceSeekableStream( rData )
233 {
234 }
235 
readData(StreamDataSequence & orData,sal_Int32 nBytes,size_t)236 sal_Int32 SequenceInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
237 {
238     sal_Int32 nReadBytes = 0;
239     if( !mbEof )
240     {
241         nReadBytes = getMaxBytes( nBytes );
242         orData.realloc( nReadBytes );
243         if( nReadBytes > 0 )
244             memcpy( orData.getArray(), mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
245         mnPos += nReadBytes;
246         mbEof = nReadBytes < nBytes;
247     }
248     return nReadBytes;
249 }
250 
readMemory(void * opMem,sal_Int32 nBytes,size_t)251 sal_Int32 SequenceInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t /*nAtomSize*/ )
252 {
253     sal_Int32 nReadBytes = 0;
254     if( !mbEof )
255     {
256         nReadBytes = getMaxBytes( nBytes );
257         if( nReadBytes > 0 )
258             memcpy( opMem, mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
259         mnPos += nReadBytes;
260         mbEof = nReadBytes < nBytes;
261     }
262     return nReadBytes;
263 }
264 
skip(sal_Int32 nBytes,size_t)265 void SequenceInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
266 {
267     if( !mbEof )
268     {
269         sal_Int32 nSkipBytes = getMaxBytes( nBytes );
270         mnPos += nSkipBytes;
271         mbEof = nSkipBytes < nBytes;
272     }
273 }
274 
275 // ============================================================================
276 
RelativeInputStream(BinaryInputStream & rInStrm,sal_Int64 nSize)277 RelativeInputStream::RelativeInputStream( BinaryInputStream& rInStrm, sal_Int64 nSize ) :
278     BinaryStreamBase( rInStrm.isSeekable() ),
279     mpInStrm( &rInStrm ),
280     mnStartPos( rInStrm.tell() ),
281     mnRelPos( 0 )
282 {
283     sal_Int64 nRemaining = rInStrm.getRemaining();
284     mnSize = (nRemaining >= 0) ? ::std::min( nSize, nRemaining ) : nSize;
285     mbEof = mbEof || rInStrm.isEof() || (mnSize < 0);
286 }
287 
size() const288 sal_Int64 RelativeInputStream::size() const
289 {
290     return mpInStrm ? mnSize : -1;
291 }
292 
tell() const293 sal_Int64 RelativeInputStream::tell() const
294 {
295     return mpInStrm ? mnRelPos : -1;
296 }
297 
seek(sal_Int64 nPos)298 void RelativeInputStream::seek( sal_Int64 nPos )
299 {
300     if( mpInStrm && isSeekable() && (mnStartPos >= 0) )
301     {
302         mnRelPos = getLimitedValue< sal_Int64, sal_Int64 >( nPos, 0, mnSize );
303         mpInStrm->seek( mnStartPos + mnRelPos );
304         mbEof = (mnRelPos != nPos) || mpInStrm->isEof();
305     }
306 }
307 
close()308 void RelativeInputStream::close()
309 {
310     mpInStrm = 0;
311     mbEof = true;
312 }
313 
readData(StreamDataSequence & orData,sal_Int32 nBytes,size_t nAtomSize)314 sal_Int32 RelativeInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
315 {
316     sal_Int32 nReadBytes = 0;
317     if( !mbEof )
318     {
319         sal_Int32 nMaxBytes = getMaxBytes( nBytes );
320         nReadBytes = mpInStrm->readData( orData, nMaxBytes, nAtomSize );
321         mnRelPos += nReadBytes;
322         mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
323     }
324     return nReadBytes;
325 }
326 
readMemory(void * opMem,sal_Int32 nBytes,size_t nAtomSize)327 sal_Int32 RelativeInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
328 {
329     sal_Int32 nReadBytes = 0;
330     if( !mbEof )
331     {
332         sal_Int32 nMaxBytes = getMaxBytes( nBytes );
333         nReadBytes = mpInStrm->readMemory( opMem, nMaxBytes, nAtomSize );
334         mnRelPos += nReadBytes;
335         mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
336     }
337     return nReadBytes;
338 }
339 
skip(sal_Int32 nBytes,size_t nAtomSize)340 void RelativeInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
341 {
342     if( !mbEof )
343     {
344         sal_Int32 nSkipBytes = getMaxBytes( nBytes );
345         mpInStrm->skip( nSkipBytes, nAtomSize );
346         mnRelPos += nSkipBytes;
347         mbEof = nSkipBytes < nBytes;
348     }
349 }
350 
351 // ============================================================================
352 
353 } // namespace oox
354