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>
35 #include <services.hxx>
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
;
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
;
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();
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)
115 , mbReachedEOF(false)
119 OTextInputStream::~OTextInputStream()
121 if( mbEncodingInitialized
)
123 rtl_destroyTextToUnicodeContext( mConvText2Unicode
, mContextText2Unicode
);
124 rtl_destroyTextToUnicodeConverter( mConvText2Unicode
);
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()
145 if( mnCharsInBuffer
== 0 && mbReachedEOF
)
151 OUString
OTextInputStream::implReadString( const Sequence
< sal_Unicode
>& Delimiters
,
152 bool bRemoveDelimiter
, bool bFindLineEnd
)
155 if( !mbEncodingInitialized
)
157 setEncoding( "utf8" );
159 if( !mbEncodingInitialized
)
162 // Only for bFindLineEnd
163 sal_Unicode cLineEndChar1
= 0x0D;
164 sal_Unicode cLineEndChar2
= 0x0A;
166 sal_Int32 nBufferReadPos
= 0;
167 sal_Int32 nCopyLen
= 0;
169 bool bFoundFirstLineEndChar
= false;
170 sal_Unicode cFirstLineEndChar
= 0;
173 // Still characters available?
174 if( nBufferReadPos
== mnCharsInBuffer
)
176 // Already reached EOF? Then we can't read any more
180 // No, so read new characters
181 if( !implReadNext() )
185 // Now there should be characters available
186 // (otherwise the loop should have been broken before)
187 sal_Unicode c
= mvBuffer
[ nBufferReadPos
++ ];
191 if( bFoundFirstLineEndChar
)
194 nCopyLen
= nBufferReadPos
- 2;
195 if( c
== cLineEndChar1
|| c
== cLineEndChar2
)
197 // Same line end char -> new line break
198 if( c
== cFirstLineEndChar
)
205 // No second line end char
209 else if( c
== cLineEndChar1
|| c
== cLineEndChar2
)
211 bFoundFirstLineEndChar
= true;
212 cFirstLineEndChar
= c
;
215 else if( comphelper::findValue(Delimiters
, c
) != -1 )
218 nCopyLen
= nBufferReadPos
;
219 if( bRemoveDelimiter
)
224 // Nothing found? Return all
225 if( !nCopyLen
&& !bFound
&& mbReachedEOF
)
226 nCopyLen
= nBufferReadPos
;
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
;
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
;
257 sal_Size nSrcCvtBytes
= 0;
258 sal_Size nTargetCount
= 0;
259 sal_Size nSourceCount
= 0;
262 const sal_Int8
*pbSource
= mSeqSource
.getConstArray();
264 // All invalid characters are transformed to the unicode undefined char
265 nTargetCount
+= rtl_convertTextToUnicode(
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
,
277 nSourceCount
+= nSrcCvtBytes
;
280 if( uiInfo
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOOSMALL
)
282 mvBuffer
.resize(mvBuffer
.size() * 2);
286 if( uiInfo
& RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOOSMALL
)
289 static Sequence
< sal_Int8
> aOneByteSeq( 1 );
290 nRead
= mxStream
->readSomeBytes( aOneByteSeq
, 1 );
297 sal_Int32 nOldLen
= mSeqSource
.getLength();
299 if( nTotalRead
> nOldLen
)
301 mSeqSource
.realloc( nTotalRead
);
303 mSeqSource
.getArray()[ nOldLen
] = aOneByteSeq
.getConstArray()[ 0 ];
312 mnCharsInBuffer
+= nTargetCount
;
315 catch( NotConnectedException
& )
318 //throw IOException( L"OTextInputStream::implReadString failed" );
320 catch( BufferSizeExceededException
& )
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
)
333 mbEncodingInitialized
= true;
334 mConvText2Unicode
= rtl_createTextToUnicodeConverter( encoding
);
335 mContextText2Unicode
= rtl_createTextToUnicodeContext( mConvText2Unicode
);
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();
369 void OTextInputStream::setInputStream( const Reference
< XInputStream
>& aStream
)
374 Reference
< XInputStream
> OTextInputStream::getInputStream()
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
};
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: */