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