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