1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
37 namespace com::sun::star::uno
{ class XComponentContext
; }
39 using namespace ::cppu
;
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::lang
;
42 using namespace ::com::sun::star::io
;
45 // Implementation XTextInputStream
47 #define INITIAL_UNICODE_BUFFER_CAPACITY 0x100
48 #define READ_BYTE_COUNT 0x100
52 class OTextInputStream
: public WeakImplHelper
< XTextInputStream2
, XServiceInfo
>
54 Reference
< XInputStream
> mxStream
;
57 bool mbEncodingInitialized
;
58 rtl_TextToUnicodeConverter mConvText2Unicode
;
59 rtl_TextToUnicodeContext mContextText2Unicode
;
60 Sequence
<sal_Int8
> mSeqSource
;
62 // Internal buffer for characters that are already converted successfully
63 std::vector
<sal_Unicode
> mvBuffer
;
64 sal_Int32 mnCharsInBuffer
;
67 /// @throws IOException
68 /// @throws RuntimeException
69 OUString
implReadString( const Sequence
< sal_Unicode
>& Delimiters
,
70 bool bRemoveDelimiter
, bool bFindLineEnd
);
71 /// @throws IOException
72 /// @throws RuntimeException
73 sal_Int32
implReadNext();
74 /// @throws RuntimeException
79 virtual ~OTextInputStream() override
;
81 // Methods XTextInputStream
82 virtual OUString SAL_CALL
readLine( ) override
;
83 virtual OUString SAL_CALL
readString( const Sequence
< sal_Unicode
>& Delimiters
, sal_Bool bRemoveDelimiter
) override
;
84 virtual sal_Bool SAL_CALL
isEOF( ) override
;
85 virtual void SAL_CALL
setEncoding( const OUString
& Encoding
) override
;
87 // Methods XInputStream
88 virtual sal_Int32 SAL_CALL
readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
) override
;
89 virtual sal_Int32 SAL_CALL
readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) override
;
90 virtual void SAL_CALL
skipBytes( sal_Int32 nBytesToSkip
) override
;
91 virtual sal_Int32 SAL_CALL
available( ) override
;
92 virtual void SAL_CALL
closeInput( ) override
;
94 // Methods XActiveDataSink
95 virtual void SAL_CALL
setInputStream( const Reference
< XInputStream
>& aStream
) override
;
96 virtual Reference
< XInputStream
> SAL_CALL
getInputStream() override
;
98 // Methods XServiceInfo
99 virtual OUString SAL_CALL
getImplementationName() override
;
100 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
101 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
106 OTextInputStream::OTextInputStream()
107 : mbEncodingInitialized(false)
108 , mConvText2Unicode(nullptr)
109 , mContextText2Unicode(nullptr)
110 , mSeqSource(READ_BYTE_COUNT
)
111 , mvBuffer(INITIAL_UNICODE_BUFFER_CAPACITY
, 0)
113 , mbReachedEOF(false)
117 OTextInputStream::~OTextInputStream()
119 if( mbEncodingInitialized
)
121 rtl_destroyTextToUnicodeContext( mConvText2Unicode
, mContextText2Unicode
);
122 rtl_destroyTextToUnicodeConverter( mConvText2Unicode
);
126 // Check uninitialized object
128 void OTextInputStream::checkNull()
130 if (mxStream
==nullptr){
131 throw RuntimeException(u
"Uninitialized object"_ustr
);
137 OUString
OTextInputStream::readLine( )
140 static Sequence
< sal_Unicode
> aDummySeq
;
141 return implReadString( aDummySeq
, true, true );
144 OUString
OTextInputStream::readString( const Sequence
< sal_Unicode
>& Delimiters
, sal_Bool bRemoveDelimiter
)
147 return implReadString( Delimiters
, bRemoveDelimiter
, false );
150 sal_Bool
OTextInputStream::isEOF()
154 if( mnCharsInBuffer
== 0 && mbReachedEOF
)
160 OUString
OTextInputStream::implReadString( const Sequence
< sal_Unicode
>& Delimiters
,
161 bool bRemoveDelimiter
, bool bFindLineEnd
)
164 if( !mbEncodingInitialized
)
166 setEncoding( u
"utf8"_ustr
);
168 if( !mbEncodingInitialized
)
171 // Only for bFindLineEnd
172 constexpr sal_Unicode cLineEndChar1
= '\r';
173 constexpr sal_Unicode cLineEndChar2
= '\n';
175 sal_Int32 nBufferReadPos
= 0;
176 sal_Int32 nCopyLen
= -1;
177 sal_Unicode cFirstLineEndChar
= 0;
180 // Still characters available?
181 if( nBufferReadPos
== mnCharsInBuffer
)
183 // Already reached EOF? Then we can't read any more
184 // Or no, so read new characters
185 if( !implReadNext() )
189 // Now there should be characters available
190 // (otherwise the loop should have been broken before)
191 sal_Unicode c
= mvBuffer
[ nBufferReadPos
++ ];
195 if (cFirstLineEndChar
!= 0)
197 assert(nCopyLen
>= 0);
198 // This is a check if the next character after a line end char is its second half
199 // Same line end char -> new line break; non-line-end char -> new line start
200 if ((c
== cFirstLineEndChar
) || (c
!= cLineEndChar1
&& c
!= cLineEndChar2
))
202 // Not a two-char line end
207 else if( c
== cLineEndChar1
|| c
== cLineEndChar2
)
209 nCopyLen
= nBufferReadPos
- 1; // we know what to copy
210 cFirstLineEndChar
= c
; // take one more loop, to check if it's a two-char line end
213 else if( comphelper::findValue(Delimiters
, c
) != -1 )
215 nCopyLen
= nBufferReadPos
;
216 if( bRemoveDelimiter
)
222 // Nothing found? Return all
224 nCopyLen
= nBufferReadPos
;
228 aRetStr
= OUString( mvBuffer
.data(), nCopyLen
);
230 // Copy rest of buffer
231 memmove( mvBuffer
.data(), mvBuffer
.data() + nBufferReadPos
,
232 (mnCharsInBuffer
- nBufferReadPos
) * sizeof( sal_Unicode
) );
233 mnCharsInBuffer
-= nBufferReadPos
;
239 sal_Int32
OTextInputStream::implReadNext()
241 // Already reached EOF? Then we can't read any more
247 if (mxStream
->readSomeBytes(mSeqSource
, READ_BYTE_COUNT
) == 0)
254 sal_uInt32 uiInfo
= mvBuffer
.size() - mnCharsInBuffer
< o3tl::make_unsigned(mSeqSource
.getLength())
255 ? RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
257 const sal_Int32 nOldCharsInBuffer
= mnCharsInBuffer
;
258 sal_Size nSourceCount
= 0;
261 if (uiInfo
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
)
263 mvBuffer
.resize(mvBuffer
.size() * 2);
266 // All invalid characters are transformed to the unicode undefined char
267 sal_Size nSrcCvtBytes
= 0;
268 mnCharsInBuffer
+= rtl_convertTextToUnicode(
270 mContextText2Unicode
,
271 reinterpret_cast<const char*>(mSeqSource
.getConstArray() + nSourceCount
),
272 mSeqSource
.getLength() - nSourceCount
,
273 mvBuffer
.data() + mnCharsInBuffer
,
274 mvBuffer
.size() - mnCharsInBuffer
,
275 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
|
276 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
277 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
,
280 nSourceCount
+= nSrcCvtBytes
;
282 if( uiInfo
& RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
)
285 Sequence
<sal_Int8
> aOneByteSeq(1);
286 if (mxStream
->readSomeBytes(aOneByteSeq
, 1) == 0)
289 return mnCharsInBuffer
- nOldCharsInBuffer
;
292 mSeqSource
= comphelper::concatSequences(mSeqSource
, aOneByteSeq
);
294 else if (!(uiInfo
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
))
295 return mnCharsInBuffer
- nOldCharsInBuffer
; // finished
298 catch( NotConnectedException
& )
300 throw IOException(u
"Not connected"_ustr
);
301 //throw IOException( L"OTextInputStream::implReadString failed" );
303 catch( BufferSizeExceededException
& )
305 throw IOException(u
"Buffer size exceeded"_ustr
);
309 void OTextInputStream::setEncoding( const OUString
& Encoding
)
311 OString aOEncodingStr
= OUStringToOString( Encoding
, RTL_TEXTENCODING_ASCII_US
);
312 rtl_TextEncoding encoding
= rtl_getTextEncodingFromMimeCharset( aOEncodingStr
.getStr() );
313 if( RTL_TEXTENCODING_DONTKNOW
== encoding
)
316 mbEncodingInitialized
= true;
317 mConvText2Unicode
= rtl_createTextToUnicodeConverter( encoding
);
318 mContextText2Unicode
= rtl_createTextToUnicodeContext( mConvText2Unicode
);
324 sal_Int32
OTextInputStream::readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
327 return mxStream
->readBytes( aData
, nBytesToRead
);
330 sal_Int32
OTextInputStream::readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
333 return mxStream
->readSomeBytes( aData
, nMaxBytesToRead
);
336 void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip
)
339 mxStream
->skipBytes( nBytesToSkip
);
342 sal_Int32
OTextInputStream::available( )
345 return mxStream
->available();
348 void OTextInputStream::closeInput( )
351 mxStream
->closeInput();
357 void OTextInputStream::setInputStream( const Reference
< XInputStream
>& aStream
)
362 Reference
< XInputStream
> OTextInputStream::getInputStream()
367 OUString
OTextInputStream::getImplementationName()
369 return u
"com.sun.star.comp.io.TextInputStream"_ustr
;
372 sal_Bool
OTextInputStream::supportsService(const OUString
& ServiceName
)
374 return cppu::supportsService(this, ServiceName
);
377 Sequence
< OUString
> OTextInputStream::getSupportedServiceNames()
379 return { u
"com.sun.star.io.TextInputStream"_ustr
};
382 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
383 io_OTextInputStream_get_implementation(
384 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
386 return cppu::acquire(new OTextInputStream());
390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */