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