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