bump product version to 6.4.0.3
[LibreOffice.git] / io / source / TextInputStream / TextInputStream.cxx
blobd90f30976ec89b883cdf520734728e90a2138e03
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
22 #include <comphelper/sequence.hxx>
23 #include <cppuhelper/implbase.hxx>
24 #include <cppuhelper/supportsservice.hxx>
26 #include <rtl/textenc.h>
27 #include <rtl/tencinfo.h>
29 #include <com/sun/star/io/BufferSizeExceededException.hpp>
30 #include <com/sun/star/io/IOException.hpp>
31 #include <com/sun/star/io/NotConnectedException.hpp>
32 #include <com/sun/star/io/XTextInputStream2.hpp>
33 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <services.hxx>
37 #include <vector>
39 namespace com::sun::star::uno { class XComponentContext; }
41 #define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
42 #define SERVICE_NAME "com.sun.star.io.TextInputStream"
44 using namespace ::osl;
45 using namespace ::cppu;
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::lang;
48 using namespace ::com::sun::star::io;
50 namespace io_TextInputStream
53 // Implementation XTextInputStream
55 #define INITIAL_UNICODE_BUFFER_CAPACITY 0x100
56 #define READ_BYTE_COUNT 0x100
58 class OTextInputStream : public WeakImplHelper< XTextInputStream2, XServiceInfo >
60 Reference< XInputStream > mxStream;
62 // Encoding
63 bool mbEncodingInitialized;
64 rtl_TextToUnicodeConverter mConvText2Unicode;
65 rtl_TextToUnicodeContext mContextText2Unicode;
66 Sequence<sal_Int8> mSeqSource;
68 // Internal buffer for characters that are already converted successfully
69 std::vector<sal_Unicode> mvBuffer;
70 sal_Int32 mnCharsInBuffer;
71 bool mbReachedEOF;
73 /// @throws IOException
74 /// @throws RuntimeException
75 OUString implReadString( const Sequence< sal_Unicode >& Delimiters,
76 bool bRemoveDelimiter, bool bFindLineEnd );
77 /// @throws IOException
78 /// @throws RuntimeException
79 sal_Int32 implReadNext();
81 public:
82 OTextInputStream();
83 virtual ~OTextInputStream() override;
85 // Methods XTextInputStream
86 virtual OUString SAL_CALL readLine( ) override;
87 virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter ) override;
88 virtual sal_Bool SAL_CALL isEOF( ) override;
89 virtual void SAL_CALL setEncoding( const OUString& Encoding ) override;
91 // Methods XInputStream
92 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
93 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
94 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
95 virtual sal_Int32 SAL_CALL available( ) override;
96 virtual void SAL_CALL closeInput( ) override;
98 // Methods XActiveDataSink
99 virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream ) override;
100 virtual Reference< XInputStream > SAL_CALL getInputStream() override;
102 // Methods XServiceInfo
103 virtual OUString SAL_CALL getImplementationName() override;
104 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
105 virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
108 OTextInputStream::OTextInputStream()
109 : mbEncodingInitialized(false)
110 , mConvText2Unicode(nullptr)
111 , mContextText2Unicode(nullptr)
112 , mSeqSource(READ_BYTE_COUNT)
113 , mvBuffer(INITIAL_UNICODE_BUFFER_CAPACITY, 0)
114 , mnCharsInBuffer(0)
115 , mbReachedEOF(false)
119 OTextInputStream::~OTextInputStream()
121 if( mbEncodingInitialized )
123 rtl_destroyTextToUnicodeContext( mConvText2Unicode, mContextText2Unicode );
124 rtl_destroyTextToUnicodeConverter( mConvText2Unicode );
129 // XTextInputStream
131 OUString OTextInputStream::readLine( )
133 static Sequence< sal_Unicode > aDummySeq;
134 return implReadString( aDummySeq, true, true );
137 OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
139 return implReadString( Delimiters, bRemoveDelimiter, false );
142 sal_Bool OTextInputStream::isEOF()
144 bool bRet = false;
145 if( mnCharsInBuffer == 0 && mbReachedEOF )
146 bRet = true;
147 return bRet;
151 OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters,
152 bool bRemoveDelimiter, bool bFindLineEnd )
154 OUString aRetStr;
155 if( !mbEncodingInitialized )
157 setEncoding( "utf8" );
159 if( !mbEncodingInitialized )
160 return aRetStr;
162 // Only for bFindLineEnd
163 sal_Unicode cLineEndChar1 = 0x0D;
164 sal_Unicode cLineEndChar2 = 0x0A;
166 sal_Int32 nBufferReadPos = 0;
167 sal_Int32 nCopyLen = 0;
168 bool bFound = false;
169 bool bFoundFirstLineEndChar = false;
170 sal_Unicode cFirstLineEndChar = 0;
171 while( !bFound )
173 // Still characters available?
174 if( nBufferReadPos == mnCharsInBuffer )
176 // Already reached EOF? Then we can't read any more
177 if( mbReachedEOF )
178 break;
180 // No, so read new characters
181 if( !implReadNext() )
182 break;
185 // Now there should be characters available
186 // (otherwise the loop should have been broken before)
187 sal_Unicode c = mvBuffer[ nBufferReadPos++ ];
189 if( bFindLineEnd )
191 if( bFoundFirstLineEndChar )
193 bFound = true;
194 nCopyLen = nBufferReadPos - 2;
195 if( c == cLineEndChar1 || c == cLineEndChar2 )
197 // Same line end char -> new line break
198 if( c == cFirstLineEndChar )
200 nBufferReadPos--;
203 else
205 // No second line end char
206 nBufferReadPos--;
209 else if( c == cLineEndChar1 || c == cLineEndChar2 )
211 bFoundFirstLineEndChar = true;
212 cFirstLineEndChar = c;
215 else if( comphelper::findValue(Delimiters, c) != -1 )
217 bFound = true;
218 nCopyLen = nBufferReadPos;
219 if( bRemoveDelimiter )
220 nCopyLen--;
224 // Nothing found? Return all
225 if( !nCopyLen && !bFound && mbReachedEOF )
226 nCopyLen = nBufferReadPos;
228 // Create string
229 if( nCopyLen )
230 aRetStr = OUString( mvBuffer.data(), nCopyLen );
232 // Copy rest of buffer
233 memmove( mvBuffer.data(), mvBuffer.data() + nBufferReadPos,
234 (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) );
235 mnCharsInBuffer -= nBufferReadPos;
237 return aRetStr;
241 sal_Int32 OTextInputStream::implReadNext()
243 sal_Int32 nFreeBufferSize = mvBuffer.size() - mnCharsInBuffer;
244 if( nFreeBufferSize < READ_BYTE_COUNT )
245 mvBuffer.resize(mvBuffer.size() * 2);
246 nFreeBufferSize = mvBuffer.size() - mnCharsInBuffer;
250 sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, READ_BYTE_COUNT );
251 sal_Int32 nTotalRead = nRead;
252 if( nRead == 0 )
253 mbReachedEOF = true;
255 // Try to convert
256 sal_uInt32 uiInfo;
257 sal_Size nSrcCvtBytes = 0;
258 sal_Size nTargetCount = 0;
259 sal_Size nSourceCount = 0;
260 while( true )
262 const sal_Int8 *pbSource = mSeqSource.getConstArray();
264 // All invalid characters are transformed to the unicode undefined char
265 nTargetCount += rtl_convertTextToUnicode(
266 mConvText2Unicode,
267 mContextText2Unicode,
268 reinterpret_cast<const char*>(&( pbSource[nSourceCount] )),
269 nTotalRead - nSourceCount,
270 mvBuffer.data() + mnCharsInBuffer + nTargetCount,
271 nFreeBufferSize - nTargetCount,
272 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
273 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
274 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
275 &uiInfo,
276 &nSrcCvtBytes );
277 nSourceCount += nSrcCvtBytes;
279 bool bCont = false;
280 if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL )
282 mvBuffer.resize(mvBuffer.size() * 2);
283 bCont = true;
286 if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL )
288 // read next byte
289 static Sequence< sal_Int8 > aOneByteSeq( 1 );
290 nRead = mxStream->readSomeBytes( aOneByteSeq, 1 );
291 if( nRead == 0 )
293 mbReachedEOF = true;
294 break;
297 sal_Int32 nOldLen = mSeqSource.getLength();
298 nTotalRead++;
299 if( nTotalRead > nOldLen )
301 mSeqSource.realloc( nTotalRead );
303 mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ];
304 bCont = true;
307 if( bCont )
308 continue;
309 break;
312 mnCharsInBuffer += nTargetCount;
313 return nTargetCount;
315 catch( NotConnectedException& )
317 throw IOException();
318 //throw IOException( L"OTextInputStream::implReadString failed" );
320 catch( BufferSizeExceededException& )
322 throw IOException();
326 void OTextInputStream::setEncoding( const OUString& Encoding )
328 OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
329 rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
330 if( RTL_TEXTENCODING_DONTKNOW == encoding )
331 return;
333 mbEncodingInitialized = true;
334 mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
335 mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
339 // XInputStream
341 sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
343 return mxStream->readBytes( aData, nBytesToRead );
346 sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
348 return mxStream->readSomeBytes( aData, nMaxBytesToRead );
351 void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
353 mxStream->skipBytes( nBytesToSkip );
356 sal_Int32 OTextInputStream::available( )
358 return mxStream->available();
361 void OTextInputStream::closeInput( )
363 mxStream->closeInput();
367 // XActiveDataSink
369 void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
371 mxStream = aStream;
374 Reference< XInputStream > OTextInputStream::getInputStream()
376 return mxStream;
380 Reference< XInterface > TextInputStream_CreateInstance(
381 SAL_UNUSED_PARAMETER const Reference< XComponentContext > &)
383 return Reference < XInterface >( static_cast<OWeakObject *>(new OTextInputStream()) );
386 OUString TextInputStream_getImplementationName()
388 return IMPLEMENTATION_NAME;
391 Sequence< OUString > TextInputStream_getSupportedServiceNames()
393 Sequence< OUString > seqNames { SERVICE_NAME };
394 return seqNames;
397 OUString OTextInputStream::getImplementationName()
399 return TextInputStream_getImplementationName();
402 sal_Bool OTextInputStream::supportsService(const OUString& ServiceName)
404 return cppu::supportsService(this, ServiceName);
407 Sequence< OUString > OTextInputStream::getSupportedServiceNames()
409 return TextInputStream_getSupportedServiceNames();
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */