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