LibreOffice Module oox (master)  1
binaryinputstream.cxx
Go to the documentation of this file.
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 
21 
22 #include <com/sun/star/io/XInputStream.hpp>
23 #include <com/sun/star/io/XSeekable.hpp>
24 #include <string.h>
25 #include <algorithm>
26 #include <vector>
27 #include <rtl/ustrbuf.hxx>
28 #include <osl/diagnose.h>
30 
31 namespace oox {
32 
33 using namespace ::com::sun::star::io;
34 using namespace ::com::sun::star::uno;
35 
36 namespace {
37 
38 const sal_Int32 INPUTSTREAM_BUFFERSIZE = 0x8000;
39 
40 } // namespace
41 
43 {
44  OUStringBuffer aBuffer;
45  for (;;)
46  {
47  sal_uInt16 nChar = readuInt16();
48  if ( mbEof || (nChar == 0) ) break;
49  aBuffer.append( static_cast< sal_Unicode >( nChar ) );
50  }
51  return aBuffer.makeStringAndClear();
52 }
53 
54 OString BinaryInputStream::readCharArray( sal_Int32 nChars )
55 {
56  if( nChars <= 0 )
57  return OString();
58 
59  ::std::vector< sal_uInt8 > aBuffer;
60  sal_Int32 nCharsRead = readArray( aBuffer, nChars );
61  if( nCharsRead <= 0 )
62  return OString();
63 
64  aBuffer.resize( static_cast< size_t >( nCharsRead ) );
65  // NUL characters are replaced by question marks.
66  ::std::replace( aBuffer.begin(), aBuffer.end(), '\0', '?' );
67 
68  return OString(reinterpret_cast<char*>(aBuffer.data()), nCharsRead);
69 }
70 
71 OUString BinaryInputStream::readCharArrayUC( sal_Int32 nChars, rtl_TextEncoding eTextEnc )
72 {
73  return OStringToOUString( readCharArray( nChars ), eTextEnc );
74 }
75 
76 OUString BinaryInputStream::readUnicodeArray( sal_Int32 nChars )
77 {
78  if( nChars <= 0 )
79  return OUString();
80 
81  ::std::vector< sal_uInt16 > aBuffer;
82  sal_Int32 nCharsRead = readArray( aBuffer, nChars );
83  if( nCharsRead <= 0 )
84  return OUString();
85 
86  aBuffer.resize( static_cast< size_t >( nCharsRead ) );
87  // don't allow nul chars
88  ::std::replace( aBuffer.begin(), aBuffer.begin() + nCharsRead, '\0', '?' );
89 
90  OUStringBuffer aStringBuffer;
91  aStringBuffer.ensureCapacity( nCharsRead );
92  for (auto const& elem : aBuffer)
93  aStringBuffer.append( static_cast< sal_Unicode >(elem) );
94  return aStringBuffer.makeStringAndClear();
95 }
96 
97 OUString BinaryInputStream::readCompressedUnicodeArray( sal_Int32 nChars, bool bCompressed )
98 {
99  return bCompressed ?
100  // ISO-8859-1 maps all byte values 0xHH to the same Unicode code point U+00HH
101  readCharArrayUC( nChars, RTL_TEXTENCODING_ISO_8859_1 ) :
102  readUnicodeArray( nChars );
103 }
104 
106 {
107  sal_Int64 nBytes = SAL_MAX_INT64;
108  sal_Int32 nBufferSize = INPUTSTREAM_BUFFERSIZE;
109  StreamDataSequence aBuffer( nBufferSize );
110  while( nBytes > 0 )
111  {
112  sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int64 >( nBytes, 0, nBufferSize );
113  sal_Int32 nBytesRead = readData( aBuffer, nReadSize );
114  rOutStrm.writeData( aBuffer );
115  if( nReadSize == nBytesRead )
116  nBytes -= nReadSize;
117  else
118  nBytes = 0;
119  }
120 }
121 
123  BinaryStreamBase( Reference< XSeekable >( rxInStrm, UNO_QUERY ).is() ),
124  BinaryXSeekableStream( Reference< XSeekable >( rxInStrm, UNO_QUERY ) ),
125  maBuffer( INPUTSTREAM_BUFFERSIZE ),
126  mxInStrm( rxInStrm ),
127  mbAutoClose( bAutoClose && rxInStrm.is() )
128 {
129  mbEof = !mxInStrm.is();
130 }
131 
133 {
134  close();
135 }
136 
138 {
139  OSL_ENSURE( !mbAutoClose || mxInStrm.is(), "BinaryXInputStream::close - invalid call" );
140  if( mxInStrm.is() ) try
141  {
142  mxInStrm->closeInput();
143  }
144  catch( Exception& )
145  {
146  OSL_FAIL( "BinaryXInputStream::close - closing input stream failed" );
147  }
148  mxInStrm.clear();
149  mbAutoClose = false;
151 }
152 
153 sal_Int32 BinaryXInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
154 {
155  sal_Int32 nRet = 0;
156  if( !mbEof && (nBytes > 0) ) try
157  {
158  nRet = mxInStrm->readBytes( orData, nBytes );
159  mbEof = nRet != nBytes;
160  }
161  catch( Exception& )
162  {
163  mbEof = true;
164  }
165  return nRet;
166 }
167 
168 sal_Int32 BinaryXInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
169 {
170  sal_Int32 nRet = 0;
171  if( !mbEof && (nBytes > 0) )
172  {
173  sal_Int32 nBufferSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, INPUTSTREAM_BUFFERSIZE );
174  sal_uInt8* opnMem = static_cast< sal_uInt8* >( opMem );
175  while( !mbEof && (nBytes > 0) )
176  {
177  sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, nBufferSize );
178  sal_Int32 nBytesRead = readData( maBuffer, nReadSize, nAtomSize );
179  if( nBytesRead > 0 )
180  memcpy( opnMem, maBuffer.getConstArray(), static_cast< size_t >( nBytesRead ) );
181  opnMem += nBytesRead;
182  nBytes -= nBytesRead;
183  nRet += nBytesRead;
184  }
185  }
186  return nRet;
187 }
188 
189 void BinaryXInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
190 {
191  if( !mbEof ) try
192  {
193  mxInStrm->skipBytes( nBytes );
194  }
195  catch( Exception& )
196  {
197  mbEof = true;
198  }
199 }
200 
202  BinaryStreamBase( true ),
203  SequenceSeekableStream( rData )
204 {
205 }
206 
207 sal_Int32 SequenceInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
208 {
209  sal_Int32 nReadBytes = 0;
210  if( !mbEof )
211  {
212  nReadBytes = getMaxBytes( nBytes );
213  orData.realloc( nReadBytes );
214  if( nReadBytes > 0 )
215  memcpy( orData.getArray(), mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
216  mnPos += nReadBytes;
217  mbEof = nReadBytes < nBytes;
218  }
219  return nReadBytes;
220 }
221 
222 sal_Int32 SequenceInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t /*nAtomSize*/ )
223 {
224  sal_Int32 nReadBytes = 0;
225  if( !mbEof )
226  {
227  nReadBytes = getMaxBytes( nBytes );
228  if( nReadBytes > 0 )
229  memcpy( opMem, mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
230  mnPos += nReadBytes;
231  mbEof = nReadBytes < nBytes;
232  }
233  return nReadBytes;
234 }
235 
236 void SequenceInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
237 {
238  if( !mbEof )
239  {
240  sal_Int32 nSkipBytes = getMaxBytes( nBytes );
241  mnPos += nSkipBytes;
242  mbEof = nSkipBytes < nBytes;
243  }
244 }
245 
247  BinaryStreamBase( rInStrm.isSeekable() ),
248  mpInStrm( &rInStrm ),
249  mnStartPos( rInStrm.tell() ),
250  mnRelPos( 0 )
251 {
252  sal_Int64 nRemaining = rInStrm.getRemaining();
253  mnSize = (nRemaining >= 0) ? ::std::min( nSize, nRemaining ) : nSize;
254  mbEof = mbEof || rInStrm.isEof() || (mnSize < 0);
255 }
256 
257 sal_Int64 RelativeInputStream::size() const
258 {
259  return mpInStrm ? mnSize : -1;
260 }
261 
262 sal_Int64 RelativeInputStream::tell() const
263 {
264  return mpInStrm ? mnRelPos : -1;
265 }
266 
267 void RelativeInputStream::seek( sal_Int64 nPos )
268 {
269  if( mpInStrm && isSeekable() && (mnStartPos >= 0) )
270  {
271  mnRelPos = getLimitedValue< sal_Int64, sal_Int64 >( nPos, 0, mnSize );
273  mbEof = (mnRelPos != nPos) || mpInStrm->isEof();
274  }
275 }
276 
278 {
279  mpInStrm = nullptr;
280  mbEof = true;
281 }
282 
283 sal_Int32 RelativeInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
284 {
285  sal_Int32 nReadBytes = 0;
286  if( !mbEof )
287  {
288  sal_Int32 nMaxBytes = getMaxBytes( nBytes );
289  nReadBytes = mpInStrm->readData( orData, nMaxBytes, nAtomSize );
290  mnRelPos += nReadBytes;
291  mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
292  }
293  return nReadBytes;
294 }
295 
296 sal_Int32 RelativeInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
297 {
298  sal_Int32 nReadBytes = 0;
299  if( !mbEof )
300  {
301  sal_Int32 nMaxBytes = getMaxBytes( nBytes );
302  nReadBytes = mpInStrm->readMemory( opMem, nMaxBytes, nAtomSize );
303  mnRelPos += nReadBytes;
304  mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
305  }
306  return nReadBytes;
307 }
308 
309 void RelativeInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
310 {
311  if( !mbEof )
312  {
313  sal_Int32 nSkipBytes = getMaxBytes( nBytes );
314  mpInStrm->skip( nSkipBytes, nAtomSize );
315  mnRelPos += nSkipBytes;
316  mbEof = nSkipBytes < nBytes;
317  }
318 }
319 
320 } // namespace oox
321 
322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual sal_Int32 readData(StreamDataSequence &orData, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the passed sequence.
virtual void close() override
Releases the reference to the UNO XSeekable interface.
Base class for binary stream classes.
virtual void close() override
Closes the input stream but not the wrapped stream.
Base class for binary input and output streams wrapping a UNO stream, seekable via the com...
SequenceInputStream(const StreamDataSequence &rData)
Constructs the wrapper object for the passed data sequence.
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1) override
Seeks the stream forward by the passed number of bytes.
virtual sal_Int32 readData(StreamDataSequence &orData, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the passed sequence.
virtual sal_Int32 readMemory(void *opMem, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the (existing) buffer opMem.
StreamDataSequence maBuffer
Data buffer used in readMemory() function.
void copyToStream(BinaryOutputStream &rOutStrm)
Copies bytes from the current position to the passed output stream.
virtual sal_Int32 readData(StreamDataSequence &orData, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the passed sequence.
Reference
virtual void close() override
Closes the input stream.
virtual void writeData(const StreamDataSequence &rData, size_t nAtomSize=1)=0
Derived classes implement writing the contents of the passed data sequence.
virtual sal_Int64 tell() const override
Returns the current relative stream position.
virtual sal_Int32 readMemory(void *opMem, sal_Int32 nBytes, size_t nAtomSize=1)=0
Derived classes implement reading nBytes bytes to the (preallocated!) memory buffer opMem...
Interface for binary output stream classes.
BinaryInputStream * mpInStrm
css::uno::Reference< css::io::XInputStream > mxInStrm
Reference to the input stream.
virtual sal_Int32 readMemory(void *opMem, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the (existing) buffer opMem.
OUString readCharArrayUC(sal_Int32 nChars, rtl_TextEncoding eTextEnc)
Reads a byte character array and returns a Unicode string.
Base class for binary input and output streams wrapping a StreamDataSequence, which is always seekabl...
Interface for binary input stream classes.
OUString readNulUnicodeArray()
Reads a NUL-terminated Unicode character array and returns the string.
RelativeInputStream(BinaryInputStream &rInStrm, sal_Int64 nSize)
Constructs the wrapper object for the passed stream.
css::uno::Sequence< sal_Int8 > StreamDataSequence
virtual void seek(sal_Int64 nPos) override
Seeks the stream to the passed relative position, if the wrapped stream is seekable.
sal_Int32 getMaxBytes(sal_Int32 nBytes) const
Returns the number of bytes available in the sequence for the passed byte count.
virtual ~BinaryXInputStream() override
bool mbEof
End of stream flag.
std::unique_ptr< char[]> aBuffer
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1) override
Seeks the stream forward by the passed number of bytes.
sal_Int64 getRemaining() const
Returns the size of the remaining data available in the stream, if stream supports size() and tell()...
virtual sal_Int64 size() const override
Returns the size of the data block in the wrapped stream offered by this wrapper. ...
virtual void seek(sal_Int64 nPos)=0
Implementations seek the stream to the passed position, if the stream is seekable.
unsigned char sal_uInt8
OString readCharArray(sal_Int32 nChars)
Reads a byte character array and returns the string.
sal_Int32 readArray(Type *opnArray, sal_Int32 nElemCount)
Reads a (preallocated!) C array of values from the stream.
bool isSeekable() const
Returns true, if the implementation supports the seek() operation.
sal_Int32 mnPos
Current position in the sequence.
bool mbAutoClose
True = automatically close stream on destruction.
OUString readUnicodeArray(sal_Int32 nChars)
Reads a Unicode character array and returns the string.
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1)=0
Derived classes implement seeking the stream forward by the passed number of bytes.
virtual sal_Int32 readData(StreamDataSequence &orData, sal_Int32 nBytes, size_t nAtomSize=1)=0
Derived classes implement reading nBytes bytes to the passed sequence.
OUString readCompressedUnicodeArray(sal_Int32 nChars, bool bCompressed)
Reads a Unicode character array (may be compressed) and returns the string.
sal_Int32 getMaxBytes(sal_Int32 nBytes) const
Returns the number of bytes available in the sequence for the passed byte count.
bool isEof() const
Returns true, if the stream position is invalid (EOF).
virtual sal_Int32 readMemory(void *opMem, sal_Int32 nBytes, size_t nAtomSize=1) override
Reads nBytes bytes to the (existing) buffer opMem.
BinaryXInputStream(const css::uno::Reference< css::io::XInputStream > &rxInStrm, bool bAutoClose)
Constructs the wrapper object for the passed input stream.
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1) override
Seeks the stream forward by the passed number of bytes.
#define SAL_MAX_INT64
const StreamDataSequence * mpData
Wrapped data sequence.