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