xref: /trunk/main/io/source/TextInputStream/TextInputStream.cxx (revision 9d37da743abb7db0a497688391f6e55a19f27c44)
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 
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 
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 
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 
152 OUString OTextInputStream::readLine(  )
153 {
154     static Sequence< sal_Unicode > aDummySeq;
155     return implReadString( aDummySeq, sal_True, sal_True );
156 }
157 
158 OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
159 {
160     return implReadString( Delimiters, bRemoveDelimiter, sal_False );
161 }
162 
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 
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 
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 
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 
380 sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
381 {
382     return mxStream->readBytes( aData, nBytesToRead );
383 }
384 
385 sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
386 {
387     return mxStream->readSomeBytes( aData, nMaxBytesToRead );
388 }
389 
390 void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
391 {
392     mxStream->skipBytes( nBytesToSkip );
393 }
394 
395 sal_Int32 OTextInputStream::available(  )
396 {
397     return mxStream->available();
398 }
399 
400 void OTextInputStream::closeInput(  )
401 {
402     mxStream->closeInput();
403 }
404 
405 
406 //===========================================================================
407 // XActiveDataSink
408 
409 void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
410 {
411     mxStream = aStream;
412 }
413 
414 Reference< XInputStream > OTextInputStream::getInputStream()
415 {
416     return mxStream;
417 }
418 
419 
420 Reference< XInterface > SAL_CALL TextInputStream_CreateInstance( const Reference< XComponentContext > &)
421 {
422     return Reference < XInterface >( ( OWeakObject * ) new OTextInputStream() );
423 }
424 
425 OUString TextInputStream_getImplementationName()
426 {
427     return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
428 }
429 
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 
446 OUString OTextInputStream::getImplementationName() throw()
447 {
448     return TextInputStream_getImplementationName();
449 }
450 
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 
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 {
484 SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
485 {
486     return g_moduleCount.canUnload( &g_moduleCount , pTime );
487 }
488 
489 //==================================================================================================
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 //==================================================================================================
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