1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: TextInputStream.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_io.hxx"
36 #include <osl/mutex.hxx>
37 #include <osl/diagnose.h>
39 #include <rtl/unload.h>
41 #include <uno/mapping.hxx>
43 #include <cppuhelper/factory.hxx>
44 #include <cppuhelper/implbase3.hxx>
45 #include <cppuhelper/implementationentry.hxx>
47 #include <rtl/textenc.h>
48 #include <rtl/tencinfo.h>
50 #include <com/sun/star/io/XTextInputStream.hpp>
51 #include <com/sun/star/io/XActiveDataSink.hpp>
52 #include <com/sun/star/lang/XServiceInfo.hpp>
55 #define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
56 #define SERVICE_NAME "com.sun.star.io.TextInputStream"
58 using namespace ::osl
;
59 using namespace ::rtl
;
60 using namespace ::cppu
;
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::io
;
64 using namespace ::com::sun::star::registry
;
66 namespace io_TextInputStream
68 rtl_StandardModuleCount g_moduleCount
= MODULE_COUNT_INIT
;
70 //===========================================================================
71 // Implementation XTextInputStream
73 typedef WeakImplHelper3
< XTextInputStream
, XActiveDataSink
, XServiceInfo
> TextInputStreamHelper
;
74 class OCommandEnvironment
;
76 #define INITIAL_UNICODE_BUFFER_CAPACITY 0x100
77 #define READ_BYTE_COUNT 0x100
79 class OTextInputStream
: public TextInputStreamHelper
81 Reference
< XInputStream
> mxStream
;
85 sal_Bool mbEncodingInitialized
;
86 rtl_TextToUnicodeConverter mConvText2Unicode
;
87 rtl_TextToUnicodeContext mContextText2Unicode
;
88 Sequence
<sal_Int8
> mSeqSource
;
90 // Internal buffer for characters that are already converted successfully
91 sal_Unicode
* mpBuffer
;
92 sal_Int32 mnBufferSize
;
93 sal_Int32 mnCharsInBuffer
;
94 sal_Bool mbReachedEOF
;
96 void implResizeBuffer( void );
97 OUString
implReadString( const Sequence
< sal_Unicode
>& Delimiters
,
98 sal_Bool bRemoveDelimiter
, sal_Bool bFindLineEnd
)
99 throw(IOException
, RuntimeException
);
100 sal_Int32
implReadNext() throw(IOException
, RuntimeException
);
104 virtual ~OTextInputStream();
106 // Methods XTextInputStream
107 virtual OUString SAL_CALL
readLine( )
108 throw(IOException
, RuntimeException
);
109 virtual OUString SAL_CALL
readString( const Sequence
< sal_Unicode
>& Delimiters
, sal_Bool bRemoveDelimiter
)
110 throw(IOException
, RuntimeException
);
111 virtual sal_Bool SAL_CALL
isEOF( )
112 throw(IOException
, RuntimeException
);
113 virtual void SAL_CALL
setEncoding( const OUString
& Encoding
) throw(RuntimeException
);
115 // Methods XInputStream
116 virtual sal_Int32 SAL_CALL
readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
117 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
);
118 virtual sal_Int32 SAL_CALL
readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
119 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
);
120 virtual void SAL_CALL
skipBytes( sal_Int32 nBytesToSkip
)
121 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
);
122 virtual sal_Int32 SAL_CALL
available( )
123 throw(NotConnectedException
, IOException
, RuntimeException
);
124 virtual void SAL_CALL
closeInput( )
125 throw(NotConnectedException
, IOException
, RuntimeException
);
127 // Methods XActiveDataSink
128 virtual void SAL_CALL
setInputStream( const Reference
< XInputStream
>& aStream
)
129 throw(RuntimeException
);
130 virtual Reference
< XInputStream
> SAL_CALL
getInputStream()
131 throw(RuntimeException
);
133 // Methods XServiceInfo
134 virtual OUString SAL_CALL
getImplementationName() throw();
135 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames(void) throw();
136 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) throw();
139 OTextInputStream::OTextInputStream()
140 : mSeqSource( READ_BYTE_COUNT
), mpBuffer( NULL
), mnBufferSize( 0 )
141 , mnCharsInBuffer( 0 ), mbReachedEOF( sal_False
)
143 g_moduleCount
.modCnt
.acquire( &g_moduleCount
.modCnt
);
144 mbEncodingInitialized
= false;
147 OTextInputStream::~OTextInputStream()
149 if( mbEncodingInitialized
)
151 rtl_destroyUnicodeToTextContext( mConvText2Unicode
, mContextText2Unicode
);
152 rtl_destroyUnicodeToTextConverter( mConvText2Unicode
);
154 g_moduleCount
.modCnt
.release( &g_moduleCount
.modCnt
);
157 void OTextInputStream::implResizeBuffer( void )
159 sal_Int32 mnNewBufferSize
= mnBufferSize
* 2;
160 sal_Unicode
* pNewBuffer
= new sal_Unicode
[ mnNewBufferSize
];
161 memcpy( pNewBuffer
, mpBuffer
, mnCharsInBuffer
* sizeof( sal_Unicode
) );
162 mpBuffer
= pNewBuffer
;
163 mnBufferSize
= mnNewBufferSize
;
167 //===========================================================================
170 OUString
OTextInputStream::readLine( )
171 throw(IOException
, RuntimeException
)
173 static Sequence
< sal_Unicode
> aDummySeq
;
174 return implReadString( aDummySeq
, sal_True
, sal_True
);
177 OUString
OTextInputStream::readString( const Sequence
< sal_Unicode
>& Delimiters
, sal_Bool
)
178 throw(IOException
, RuntimeException
)
180 return implReadString( Delimiters
, sal_True
, sal_False
);
183 sal_Bool
OTextInputStream::isEOF()
184 throw(IOException
, RuntimeException
)
186 sal_Bool bRet
= sal_False
;
187 if( mnCharsInBuffer
== 0 && mbReachedEOF
)
193 OUString
OTextInputStream::implReadString( const Sequence
< sal_Unicode
>& Delimiters
,
194 sal_Bool bRemoveDelimiter
, sal_Bool bFindLineEnd
)
195 throw(IOException
, RuntimeException
)
198 if( !mbEncodingInitialized
)
200 OUString
aUtf8Str( RTL_CONSTASCII_USTRINGPARAM("utf8") );
201 setEncoding( aUtf8Str
);
203 if( !mbEncodingInitialized
)
208 mnBufferSize
= INITIAL_UNICODE_BUFFER_CAPACITY
;
209 mpBuffer
= new sal_Unicode
[ mnBufferSize
];
212 // Only for bFindLineEnd
213 sal_Unicode cLineEndChar1
= 0x0D;
214 sal_Unicode cLineEndChar2
= 0x0A;
216 sal_Int32 nBufferReadPos
= 0;
217 sal_Int32 nCopyLen
= 0;
218 sal_Bool bFound
= sal_False
;
219 sal_Bool bFoundFirstLineEndChar
= sal_False
;
220 sal_Unicode cFirstLineEndChar
= 0;
221 const sal_Unicode
* pDelims
= Delimiters
.getConstArray();
222 const sal_Int32 nDelimCount
= Delimiters
.getLength();
225 // Still characters available?
226 if( nBufferReadPos
== mnCharsInBuffer
)
228 // Already reached EOF? Then we can't read any more
232 // No, so read new characters
233 if( !implReadNext() )
237 // Now there should be characters available
238 // (otherwise the loop should have been breaked before)
239 sal_Unicode c
= mpBuffer
[ nBufferReadPos
++ ];
243 if( bFoundFirstLineEndChar
)
246 nCopyLen
= nBufferReadPos
- 2;
247 if( c
== cLineEndChar1
|| c
== cLineEndChar2
)
249 // Same line end char -> new line break
250 if( c
== cFirstLineEndChar
)
257 // No second line end char
261 else if( c
== cLineEndChar1
|| c
== cLineEndChar2
)
263 bFoundFirstLineEndChar
= sal_True
;
264 cFirstLineEndChar
= c
;
269 for( sal_Int32 i
= 0 ; i
< nDelimCount
; i
++ )
271 if( c
== pDelims
[ i
] )
274 nCopyLen
= nBufferReadPos
;
275 if( bRemoveDelimiter
)
282 // Nothing found? Return all
283 if( !nCopyLen
&& !bFound
&& mbReachedEOF
)
284 nCopyLen
= nBufferReadPos
;
288 aRetStr
= OUString( mpBuffer
, nCopyLen
);
290 // Copy rest of buffer
291 memmove( mpBuffer
, mpBuffer
+ nBufferReadPos
,
292 (mnCharsInBuffer
- nBufferReadPos
) * sizeof( sal_Unicode
) );
293 mnCharsInBuffer
-= nBufferReadPos
;
299 sal_Int32
OTextInputStream::implReadNext()
300 throw(IOException
, RuntimeException
)
302 sal_Int32 nFreeBufferSize
= mnBufferSize
- mnCharsInBuffer
;
303 if( nFreeBufferSize
< READ_BYTE_COUNT
)
305 nFreeBufferSize
= mnBufferSize
- mnCharsInBuffer
;
309 sal_Int32 nBytesToRead
= READ_BYTE_COUNT
;
310 sal_Int32 nRead
= mxStream
->readSomeBytes( mSeqSource
, nBytesToRead
);
311 sal_Int32 nTotalRead
= nRead
;
312 if( nRead
< nBytesToRead
)
313 mbReachedEOF
= sal_True
;
317 sal_Size nSrcCvtBytes
= 0;
318 sal_Size nTargetCount
= 0;
319 sal_Size nSourceCount
= 0;
322 const sal_Int8
*pbSource
= mSeqSource
.getConstArray();
324 // All invalid characters are transformed to the unicode undefined char
325 nTargetCount
+= rtl_convertTextToUnicode(
327 mContextText2Unicode
,
328 (const sal_Char
*) &( pbSource
[nSourceCount
] ),
329 nTotalRead
- nSourceCount
,
330 mpBuffer
+ mnCharsInBuffer
+ nTargetCount
,
331 nFreeBufferSize
- nTargetCount
,
332 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
|
333 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
334 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
,
337 nSourceCount
+= nSrcCvtBytes
;
339 sal_Bool bCont
= sal_False
;
340 if( uiInfo
& RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL
)
346 if( uiInfo
& RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL
)
349 static Sequence
< sal_Int8
> aOneByteSeq( 1 );
350 nRead
= mxStream
->readSomeBytes( aOneByteSeq
, 1 );
353 mbReachedEOF
= sal_True
;
357 sal_Int32 nOldLen
= mSeqSource
.getLength();
359 if( nTotalRead
> nOldLen
)
361 mSeqSource
.realloc( nTotalRead
);
363 mSeqSource
.getArray()[ nOldLen
] = aOneByteSeq
.getConstArray()[ 0 ];
364 pbSource
= mSeqSource
.getConstArray();
373 mnCharsInBuffer
+= nTargetCount
;
376 catch( NotConnectedException
& )
379 //throw IOException( L"OTextInputStream::implReadString failed" );
381 catch( BufferSizeExceededException
& )
387 void OTextInputStream::setEncoding( const OUString
& Encoding
)
388 throw(RuntimeException
)
390 OString aOEncodingStr
= OUStringToOString( Encoding
, RTL_TEXTENCODING_ASCII_US
);
391 rtl_TextEncoding encoding
= rtl_getTextEncodingFromMimeCharset( aOEncodingStr
.getStr() );
392 if( RTL_TEXTENCODING_DONTKNOW
== encoding
)
395 mbEncodingInitialized
= true;
396 mConvText2Unicode
= rtl_createTextToUnicodeConverter( encoding
);
397 mContextText2Unicode
= rtl_createTextToUnicodeContext( mConvText2Unicode
);
398 mEncoding
= Encoding
;
401 //===========================================================================
404 sal_Int32
OTextInputStream::readBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
405 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
)
407 return mxStream
->readBytes( aData
, nBytesToRead
);
410 sal_Int32
OTextInputStream::readSomeBytes( Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
411 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
)
413 return mxStream
->readSomeBytes( aData
, nMaxBytesToRead
);
416 void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip
)
417 throw(NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
)
419 mxStream
->skipBytes( nBytesToSkip
);
422 sal_Int32
OTextInputStream::available( )
423 throw(NotConnectedException
, IOException
, RuntimeException
)
425 return mxStream
->available();
428 void OTextInputStream::closeInput( )
429 throw(NotConnectedException
, IOException
, RuntimeException
)
431 mxStream
->closeInput();
435 //===========================================================================
438 void OTextInputStream::setInputStream( const Reference
< XInputStream
>& aStream
)
439 throw(RuntimeException
)
444 Reference
< XInputStream
> OTextInputStream::getInputStream()
445 throw(RuntimeException
)
451 Reference
< XInterface
> SAL_CALL
TextInputStream_CreateInstance( const Reference
< XComponentContext
> &)
453 return Reference
< XInterface
>( ( OWeakObject
* ) new OTextInputStream() );
456 OUString
TextInputStream_getImplementationName()
458 return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME
) );
461 Sequence
< OUString
> TextInputStream_getSupportedServiceNames()
463 static Sequence
< OUString
> *pNames
= 0;
466 MutexGuard
guard( Mutex::getGlobalMutex() );
469 static Sequence
< OUString
> seqNames(1);
470 seqNames
.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME
) );
477 OUString
OTextInputStream::getImplementationName() throw()
479 return TextInputStream_getImplementationName();
482 sal_Bool
OTextInputStream::supportsService(const OUString
& ServiceName
) throw()
484 Sequence
< OUString
> aSNL
= getSupportedServiceNames();
485 const OUString
* pArray
= aSNL
.getConstArray();
487 for( sal_Int32 i
= 0; i
< aSNL
.getLength(); i
++ )
488 if( pArray
[i
] == ServiceName
)
494 Sequence
< OUString
> OTextInputStream::getSupportedServiceNames(void) throw()
496 return TextInputStream_getSupportedServiceNames();
501 using namespace io_TextInputStream
;
503 static struct ImplementationEntry g_entries
[] =
506 TextInputStream_CreateInstance
, TextInputStream_getImplementationName
,
507 TextInputStream_getSupportedServiceNames
, createSingleComponentFactory
,
508 &g_moduleCount
.modCnt
, 0
515 sal_Bool SAL_CALL
component_canUnload( TimeValue
*pTime
)
517 return g_moduleCount
.canUnload( &g_moduleCount
, pTime
);
520 //==================================================================================================
521 void SAL_CALL
component_getImplementationEnvironment(
522 const sal_Char
** ppEnvTypeName
, uno_Environment
** )
524 *ppEnvTypeName
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
;
526 //==================================================================================================
527 sal_Bool SAL_CALL
component_writeInfo(
528 void * pServiceManager
, void * pRegistryKey
)
530 return component_writeInfoHelper( pServiceManager
, pRegistryKey
, g_entries
);
532 //==================================================================================================
533 void * SAL_CALL
component_getFactory(
534 const sal_Char
* pImplName
, void * pServiceManager
, void * pRegistryKey
)
536 return component_getFactoryHelper( pImplName
, pServiceManager
, pRegistryKey
, g_entries
);