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