Line data Source code
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 :
20 : #include <string.h>
21 : #include <osl/diagnose.h>
22 :
23 : #include <uno/mapping.hxx>
24 :
25 : #include <cppuhelper/factory.hxx>
26 : #include <cppuhelper/implbase2.hxx>
27 : #include <cppuhelper/implementationentry.hxx>
28 : #include <cppuhelper/supportsservice.hxx>
29 :
30 : #include <rtl/textenc.h>
31 : #include <rtl/tencinfo.h>
32 :
33 : #include <com/sun/star/io/XTextInputStream2.hpp>
34 : #include <com/sun/star/lang/XServiceInfo.hpp>
35 :
36 : #include "services.hxx"
37 :
38 : #define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
39 : #define SERVICE_NAME "com.sun.star.io.TextInputStream"
40 :
41 : using namespace ::osl;
42 : using namespace ::rtl;
43 : using namespace ::cppu;
44 : using namespace ::com::sun::star::uno;
45 : using namespace ::com::sun::star::lang;
46 : using namespace ::com::sun::star::io;
47 : using namespace ::com::sun::star::registry;
48 :
49 : namespace io_TextInputStream
50 : {
51 :
52 : // Implementation XTextInputStream
53 :
54 : typedef WeakImplHelper2< XTextInputStream2, XServiceInfo > TextInputStreamHelper;
55 :
56 : #define INITIAL_UNICODE_BUFFER_CAPACITY 0x100
57 : #define READ_BYTE_COUNT 0x100
58 :
59 : class OTextInputStream : public TextInputStreamHelper
60 : {
61 : Reference< XInputStream > mxStream;
62 :
63 : // Encoding
64 : OUString mEncoding;
65 : sal_Bool mbEncodingInitialized;
66 : rtl_TextToUnicodeConverter mConvText2Unicode;
67 : rtl_TextToUnicodeContext mContextText2Unicode;
68 : Sequence<sal_Int8> mSeqSource;
69 :
70 : // Internal buffer for characters that are already converted successfully
71 : sal_Unicode* mpBuffer;
72 : sal_Int32 mnBufferSize;
73 : sal_Int32 mnCharsInBuffer;
74 : sal_Bool mbReachedEOF;
75 :
76 : void implResizeBuffer( void );
77 : OUString implReadString( const Sequence< sal_Unicode >& Delimiters,
78 : sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
79 : throw(IOException, RuntimeException);
80 : sal_Int32 implReadNext() throw(IOException, RuntimeException);
81 :
82 : public:
83 : OTextInputStream();
84 : virtual ~OTextInputStream();
85 :
86 : // Methods XTextInputStream
87 : virtual OUString SAL_CALL readLine( )
88 : throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
89 : virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
90 : throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
91 : virtual sal_Bool SAL_CALL isEOF( )
92 : throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
93 : virtual void SAL_CALL setEncoding( const OUString& Encoding ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
94 :
95 : // Methods XInputStream
96 : virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
97 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
98 : virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
99 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
100 : virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
101 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
102 : virtual sal_Int32 SAL_CALL available( )
103 : throw(NotConnectedException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
104 : virtual void SAL_CALL closeInput( )
105 : throw(NotConnectedException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
106 :
107 : // Methods XActiveDataSink
108 : virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream )
109 : throw(RuntimeException, std::exception) SAL_OVERRIDE;
110 : virtual Reference< XInputStream > SAL_CALL getInputStream()
111 : throw(RuntimeException, std::exception) SAL_OVERRIDE;
112 :
113 : // Methods XServiceInfo
114 : virtual OUString SAL_CALL getImplementationName() throw(std::exception) SAL_OVERRIDE;
115 : virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw(std::exception) SAL_OVERRIDE;
116 : virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw(std::exception) SAL_OVERRIDE;
117 : };
118 :
119 0 : OTextInputStream::OTextInputStream()
120 : : mbEncodingInitialized(false)
121 : , mConvText2Unicode(NULL)
122 : , mContextText2Unicode(NULL)
123 : , mSeqSource(READ_BYTE_COUNT)
124 : , mpBuffer(NULL)
125 : , mnBufferSize(0)
126 : , mnCharsInBuffer(0)
127 0 : , mbReachedEOF(sal_False)
128 : {
129 0 : }
130 :
131 0 : OTextInputStream::~OTextInputStream()
132 : {
133 0 : if( mbEncodingInitialized )
134 : {
135 0 : rtl_destroyUnicodeToTextContext( mConvText2Unicode, mContextText2Unicode );
136 0 : rtl_destroyUnicodeToTextConverter( mConvText2Unicode );
137 : }
138 :
139 0 : delete[] mpBuffer;
140 0 : }
141 :
142 0 : void OTextInputStream::implResizeBuffer( void )
143 : {
144 0 : sal_Int32 mnNewBufferSize = mnBufferSize * 2;
145 0 : sal_Unicode* pNewBuffer = new sal_Unicode[ mnNewBufferSize ];
146 0 : memcpy( pNewBuffer, mpBuffer, mnCharsInBuffer * sizeof( sal_Unicode ) );
147 0 : delete[] mpBuffer;
148 0 : mpBuffer = pNewBuffer;
149 0 : mnBufferSize = mnNewBufferSize;
150 0 : }
151 :
152 :
153 :
154 : // XTextInputStream
155 :
156 0 : OUString OTextInputStream::readLine( )
157 : throw(IOException, RuntimeException, std::exception)
158 : {
159 0 : static Sequence< sal_Unicode > aDummySeq;
160 0 : return implReadString( aDummySeq, sal_True, sal_True );
161 : }
162 :
163 0 : OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
164 : throw(IOException, RuntimeException, std::exception)
165 : {
166 0 : return implReadString( Delimiters, bRemoveDelimiter, sal_False );
167 : }
168 :
169 0 : sal_Bool OTextInputStream::isEOF()
170 : throw(IOException, RuntimeException, std::exception)
171 : {
172 0 : sal_Bool bRet = sal_False;
173 0 : if( mnCharsInBuffer == 0 && mbReachedEOF )
174 0 : bRet = sal_True;
175 0 : return bRet;
176 : }
177 :
178 :
179 0 : OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters,
180 : sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
181 : throw(IOException, RuntimeException)
182 : {
183 0 : OUString aRetStr;
184 0 : if( !mbEncodingInitialized )
185 : {
186 0 : OUString aUtf8Str("utf8");
187 0 : setEncoding( aUtf8Str );
188 : }
189 0 : if( !mbEncodingInitialized )
190 0 : return aRetStr;
191 :
192 0 : if( !mpBuffer )
193 : {
194 0 : mnBufferSize = INITIAL_UNICODE_BUFFER_CAPACITY;
195 0 : mpBuffer = new sal_Unicode[ mnBufferSize ];
196 : }
197 :
198 : // Only for bFindLineEnd
199 0 : sal_Unicode cLineEndChar1 = 0x0D;
200 0 : sal_Unicode cLineEndChar2 = 0x0A;
201 :
202 0 : sal_Int32 nBufferReadPos = 0;
203 0 : sal_Int32 nCopyLen = 0;
204 0 : sal_Bool bFound = sal_False;
205 0 : sal_Bool bFoundFirstLineEndChar = sal_False;
206 0 : sal_Unicode cFirstLineEndChar = 0;
207 0 : const sal_Unicode* pDelims = Delimiters.getConstArray();
208 0 : const sal_Int32 nDelimCount = Delimiters.getLength();
209 0 : while( !bFound )
210 : {
211 : // Still characters available?
212 0 : if( nBufferReadPos == mnCharsInBuffer )
213 : {
214 : // Already reached EOF? Then we can't read any more
215 0 : if( mbReachedEOF )
216 0 : break;
217 :
218 : // No, so read new characters
219 0 : if( !implReadNext() )
220 0 : break;
221 : }
222 :
223 : // Now there should be characters available
224 : // (otherwise the loop should have been breaked before)
225 0 : sal_Unicode c = mpBuffer[ nBufferReadPos++ ];
226 :
227 0 : if( bFindLineEnd )
228 : {
229 0 : if( bFoundFirstLineEndChar )
230 : {
231 0 : bFound = sal_True;
232 0 : nCopyLen = nBufferReadPos - 2;
233 0 : if( c == cLineEndChar1 || c == cLineEndChar2 )
234 : {
235 : // Same line end char -> new line break
236 0 : if( c == cFirstLineEndChar )
237 : {
238 0 : nBufferReadPos--;
239 : }
240 : }
241 : else
242 : {
243 : // No second line end char
244 0 : nBufferReadPos--;
245 : }
246 : }
247 0 : else if( c == cLineEndChar1 || c == cLineEndChar2 )
248 : {
249 0 : bFoundFirstLineEndChar = sal_True;
250 0 : cFirstLineEndChar = c;
251 : }
252 : }
253 : else
254 : {
255 0 : for( sal_Int32 i = 0 ; i < nDelimCount ; i++ )
256 : {
257 0 : if( c == pDelims[ i ] )
258 : {
259 0 : bFound = sal_True;
260 0 : nCopyLen = nBufferReadPos;
261 0 : if( bRemoveDelimiter )
262 0 : nCopyLen--;
263 : }
264 : }
265 : }
266 : }
267 :
268 : // Nothing found? Return all
269 0 : if( !nCopyLen && !bFound && mbReachedEOF )
270 0 : nCopyLen = nBufferReadPos;
271 :
272 : // Create string
273 0 : if( nCopyLen )
274 0 : aRetStr = OUString( mpBuffer, nCopyLen );
275 :
276 : // Copy rest of buffer
277 : memmove( mpBuffer, mpBuffer + nBufferReadPos,
278 0 : (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) );
279 0 : mnCharsInBuffer -= nBufferReadPos;
280 :
281 0 : return aRetStr;
282 : }
283 :
284 :
285 0 : sal_Int32 OTextInputStream::implReadNext()
286 : throw(IOException, RuntimeException)
287 : {
288 0 : sal_Int32 nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
289 0 : if( nFreeBufferSize < READ_BYTE_COUNT )
290 0 : implResizeBuffer();
291 0 : nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
292 :
293 : try
294 : {
295 0 : sal_Int32 nBytesToRead = READ_BYTE_COUNT;
296 0 : sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, nBytesToRead );
297 0 : sal_Int32 nTotalRead = nRead;
298 0 : if( nRead < nBytesToRead )
299 0 : mbReachedEOF = sal_True;
300 :
301 : // Try to convert
302 : sal_uInt32 uiInfo;
303 0 : sal_Size nSrcCvtBytes = 0;
304 0 : sal_Size nTargetCount = 0;
305 0 : sal_Size nSourceCount = 0;
306 : while( true )
307 : {
308 0 : const sal_Int8 *pbSource = mSeqSource.getConstArray();
309 :
310 : // All invalid characters are transformed to the unicode undefined char
311 : nTargetCount += rtl_convertTextToUnicode(
312 : mConvText2Unicode,
313 : mContextText2Unicode,
314 : (const sal_Char*) &( pbSource[nSourceCount] ),
315 : nTotalRead - nSourceCount,
316 0 : mpBuffer + mnCharsInBuffer + nTargetCount,
317 : nFreeBufferSize - nTargetCount,
318 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
319 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
320 : RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
321 : &uiInfo,
322 0 : &nSrcCvtBytes );
323 0 : nSourceCount += nSrcCvtBytes;
324 :
325 0 : sal_Bool bCont = sal_False;
326 0 : if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL )
327 : {
328 0 : implResizeBuffer();
329 0 : bCont = sal_True;
330 : }
331 :
332 0 : if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL )
333 : {
334 : // read next byte
335 0 : static Sequence< sal_Int8 > aOneByteSeq( 1 );
336 0 : nRead = mxStream->readSomeBytes( aOneByteSeq, 1 );
337 0 : if( nRead == 0 )
338 : {
339 0 : mbReachedEOF = sal_True;
340 0 : break;
341 : }
342 :
343 0 : sal_Int32 nOldLen = mSeqSource.getLength();
344 0 : nTotalRead++;
345 0 : if( nTotalRead > nOldLen )
346 : {
347 0 : mSeqSource.realloc( nTotalRead );
348 : }
349 0 : mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ];
350 0 : pbSource = mSeqSource.getConstArray();
351 0 : bCont = sal_True;
352 : }
353 :
354 0 : if( bCont )
355 0 : continue;
356 0 : break;
357 : }
358 :
359 0 : mnCharsInBuffer += nTargetCount;
360 0 : return nTargetCount;
361 : }
362 0 : catch( NotConnectedException& )
363 : {
364 0 : throw IOException();
365 : //throw IOException( L"OTextInputStream::implReadString failed" );
366 : }
367 0 : catch( BufferSizeExceededException& )
368 : {
369 0 : throw IOException();
370 : }
371 : }
372 :
373 0 : void OTextInputStream::setEncoding( const OUString& Encoding )
374 : throw(RuntimeException, std::exception)
375 : {
376 0 : OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
377 0 : rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
378 0 : if( RTL_TEXTENCODING_DONTKNOW == encoding )
379 0 : return;
380 :
381 0 : mbEncodingInitialized = true;
382 0 : mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
383 0 : mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
384 0 : mEncoding = Encoding;
385 : }
386 :
387 :
388 : // XInputStream
389 :
390 0 : sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
391 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
392 : {
393 0 : return mxStream->readBytes( aData, nBytesToRead );
394 : }
395 :
396 0 : sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
397 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
398 : {
399 0 : return mxStream->readSomeBytes( aData, nMaxBytesToRead );
400 : }
401 :
402 0 : void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
403 : throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
404 : {
405 0 : mxStream->skipBytes( nBytesToSkip );
406 0 : }
407 :
408 0 : sal_Int32 OTextInputStream::available( )
409 : throw(NotConnectedException, IOException, RuntimeException, std::exception)
410 : {
411 0 : return mxStream->available();
412 : }
413 :
414 0 : void OTextInputStream::closeInput( )
415 : throw(NotConnectedException, IOException, RuntimeException, std::exception)
416 : {
417 0 : mxStream->closeInput();
418 0 : }
419 :
420 :
421 :
422 : // XActiveDataSink
423 :
424 0 : void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
425 : throw(RuntimeException, std::exception)
426 : {
427 0 : mxStream = aStream;
428 0 : }
429 :
430 0 : Reference< XInputStream > OTextInputStream::getInputStream()
431 : throw(RuntimeException, std::exception)
432 : {
433 0 : return mxStream;
434 : }
435 :
436 :
437 0 : Reference< XInterface > SAL_CALL TextInputStream_CreateInstance(
438 : SAL_UNUSED_PARAMETER const Reference< XComponentContext > &)
439 : {
440 0 : return Reference < XInterface >( ( OWeakObject * ) new OTextInputStream() );
441 : }
442 :
443 0 : OUString TextInputStream_getImplementationName()
444 : {
445 0 : return OUString ( IMPLEMENTATION_NAME );
446 : }
447 :
448 0 : Sequence< OUString > TextInputStream_getSupportedServiceNames()
449 : {
450 0 : Sequence< OUString > seqNames(1);
451 0 : seqNames.getArray()[0] = SERVICE_NAME;
452 0 : return seqNames;
453 : }
454 :
455 0 : OUString OTextInputStream::getImplementationName() throw(std::exception)
456 : {
457 0 : return TextInputStream_getImplementationName();
458 : }
459 :
460 0 : sal_Bool OTextInputStream::supportsService(const OUString& ServiceName) throw(std::exception)
461 : {
462 0 : return cppu::supportsService(this, ServiceName);
463 : }
464 :
465 0 : Sequence< OUString > OTextInputStream::getSupportedServiceNames(void) throw(std::exception)
466 : {
467 0 : return TextInputStream_getSupportedServiceNames();
468 : }
469 :
470 : }
471 :
472 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|