LCOV - code coverage report
Current view: top level - libreoffice/io/source/TextInputStream - TextInputStream.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 115 171 67.3 %
Date: 2012-12-27 Functions: 15 25 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <string.h>
      21             : #include <osl/diagnose.h>
      22             : 
      23             : #include <rtl/unload.h>
      24             : 
      25             : #include <uno/mapping.hxx>
      26             : 
      27             : #include <cppuhelper/factory.hxx>
      28             : #include <cppuhelper/implbase3.hxx>
      29             : #include <cppuhelper/implementationentry.hxx>
      30             : 
      31             : #include <rtl/textenc.h>
      32             : #include <rtl/tencinfo.h>
      33             : 
      34             : #include <com/sun/star/io/XTextInputStream.hpp>
      35             : #include <com/sun/star/io/XActiveDataSink.hpp>
      36             : #include <com/sun/star/lang/XServiceInfo.hpp>
      37             : 
      38             : 
      39             : #define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
      40             : #define SERVICE_NAME "com.sun.star.io.TextInputStream"
      41             : 
      42             : using namespace ::osl;
      43             : using namespace ::rtl;
      44             : using namespace ::cppu;
      45             : using namespace ::com::sun::star::uno;
      46             : using namespace ::com::sun::star::lang;
      47             : using namespace ::com::sun::star::io;
      48             : using namespace ::com::sun::star::registry;
      49             : 
      50             : namespace io_TextInputStream
      51             : {
      52             :     rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;
      53             : 
      54             : //===========================================================================
      55             : // Implementation XTextInputStream
      56             : 
      57             : typedef WeakImplHelper3< XTextInputStream, XActiveDataSink, XServiceInfo > TextInputStreamHelper;
      58             : 
      59             : #define INITIAL_UNICODE_BUFFER_CAPACITY     0x100
      60             : #define READ_BYTE_COUNT                     0x100
      61             : 
      62             : class OTextInputStream : public TextInputStreamHelper
      63             : {
      64             :     Reference< XInputStream > mxStream;
      65             : 
      66             :     // Encoding
      67             :     OUString mEncoding;
      68             :     sal_Bool mbEncodingInitialized;
      69             :     rtl_TextToUnicodeConverter  mConvText2Unicode;
      70             :     rtl_TextToUnicodeContext    mContextText2Unicode;
      71             :     Sequence<sal_Int8>          mSeqSource;
      72             : 
      73             :     // Internal buffer for characters that are already converted successfully
      74             :     sal_Unicode* mpBuffer;
      75             :     sal_Int32 mnBufferSize;
      76             :     sal_Int32 mnCharsInBuffer;
      77             :     sal_Bool mbReachedEOF;
      78             : 
      79             :     void implResizeBuffer( void );
      80             :     OUString implReadString( const Sequence< sal_Unicode >& Delimiters,
      81             :         sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
      82             :             throw(IOException, RuntimeException);
      83             :     sal_Int32 implReadNext() throw(IOException, RuntimeException);
      84             : 
      85             : public:
      86             :     OTextInputStream();
      87             :     virtual ~OTextInputStream();
      88             : 
      89             :     // Methods XTextInputStream
      90             :     virtual OUString SAL_CALL readLine(  )
      91             :         throw(IOException, RuntimeException);
      92             :     virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
      93             :         throw(IOException, RuntimeException);
      94             :     virtual sal_Bool SAL_CALL isEOF(  )
      95             :         throw(IOException, RuntimeException);
      96             :     virtual void SAL_CALL setEncoding( const OUString& Encoding ) throw(RuntimeException);
      97             : 
      98             :     // Methods XInputStream
      99             :     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
     100             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
     101             :     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
     102             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
     103             :     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
     104             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
     105             :     virtual sal_Int32 SAL_CALL available(  )
     106             :         throw(NotConnectedException, IOException, RuntimeException);
     107             :     virtual void SAL_CALL closeInput(  )
     108             :         throw(NotConnectedException, IOException, RuntimeException);
     109             : 
     110             :     // Methods XActiveDataSink
     111             :     virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream )
     112             :         throw(RuntimeException);
     113             :     virtual Reference< XInputStream > SAL_CALL getInputStream()
     114             :         throw(RuntimeException);
     115             : 
     116             :     // Methods XServiceInfo
     117             :         virtual OUString              SAL_CALL getImplementationName() throw();
     118             :         virtual Sequence< OUString >  SAL_CALL getSupportedServiceNames(void) throw();
     119             :         virtual sal_Bool              SAL_CALL supportsService(const OUString& ServiceName) throw();
     120             : };
     121             : 
     122          20 : OTextInputStream::OTextInputStream()
     123             :     : mSeqSource( READ_BYTE_COUNT ), mpBuffer( NULL ), mnBufferSize( 0 )
     124          20 :     , mnCharsInBuffer( 0 ), mbReachedEOF( sal_False )
     125             : {
     126          20 :     g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
     127          20 :     mbEncodingInitialized = false;
     128          20 : }
     129             : 
     130          60 : OTextInputStream::~OTextInputStream()
     131             : {
     132          20 :     if( mbEncodingInitialized )
     133             :     {
     134          20 :         rtl_destroyUnicodeToTextContext( mConvText2Unicode, mContextText2Unicode );
     135          20 :         rtl_destroyUnicodeToTextConverter( mConvText2Unicode );
     136             :     }
     137          20 :     g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
     138          40 : }
     139             : 
     140          20 : void OTextInputStream::implResizeBuffer( void )
     141             : {
     142          20 :     sal_Int32 mnNewBufferSize = mnBufferSize * 2;
     143          20 :     sal_Unicode* pNewBuffer = new sal_Unicode[ mnNewBufferSize ];
     144          20 :     memcpy( pNewBuffer, mpBuffer, mnCharsInBuffer * sizeof( sal_Unicode ) );
     145          20 :     mpBuffer = pNewBuffer;
     146          20 :     mnBufferSize = mnNewBufferSize;
     147          20 : }
     148             : 
     149             : 
     150             : //===========================================================================
     151             : // XTextInputStream
     152             : 
     153         493 : OUString OTextInputStream::readLine(  )
     154             :     throw(IOException, RuntimeException)
     155             : {
     156         493 :     static Sequence< sal_Unicode > aDummySeq;
     157         493 :     return implReadString( aDummySeq, sal_True, sal_True );
     158             : }
     159             : 
     160         130 : OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
     161             :         throw(IOException, RuntimeException)
     162             : {
     163         130 :     return implReadString( Delimiters, bRemoveDelimiter, sal_False );
     164             : }
     165             : 
     166         707 : sal_Bool OTextInputStream::isEOF()
     167             :     throw(IOException, RuntimeException)
     168             : {
     169         707 :     sal_Bool bRet = sal_False;
     170         707 :     if( mnCharsInBuffer == 0 && mbReachedEOF )
     171          19 :         bRet = sal_True;
     172         707 :     return bRet;
     173             : }
     174             : 
     175             : 
     176         623 : OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters,
     177             :                                            sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
     178             :         throw(IOException, RuntimeException)
     179             : {
     180         623 :     OUString aRetStr;
     181         623 :     if( !mbEncodingInitialized )
     182             :     {
     183           0 :         OUString aUtf8Str("utf8");
     184           0 :         setEncoding( aUtf8Str );
     185             :     }
     186         623 :     if( !mbEncodingInitialized )
     187           0 :         return aRetStr;
     188             : 
     189         623 :     if( !mpBuffer )
     190             :     {
     191          20 :         mnBufferSize = INITIAL_UNICODE_BUFFER_CAPACITY;
     192          20 :         mpBuffer = new sal_Unicode[ mnBufferSize ];
     193             :     }
     194             : 
     195             :     // Only for bFindLineEnd
     196         623 :     sal_Unicode cLineEndChar1 = 0x0D;
     197         623 :     sal_Unicode cLineEndChar2 = 0x0A;
     198             : 
     199         623 :     sal_Int32 nBufferReadPos = 0;
     200         623 :     sal_Int32 nCopyLen = 0;
     201         623 :     sal_Bool bFound = sal_False;
     202         623 :     sal_Bool bFoundFirstLineEndChar = sal_False;
     203         623 :     sal_Unicode cFirstLineEndChar = 0;
     204         623 :     const sal_Unicode* pDelims = Delimiters.getConstArray();
     205         623 :     const sal_Int32 nDelimCount = Delimiters.getLength();
     206       19356 :     while( !bFound )
     207             :     {
     208             :         // Still characters available?
     209       18110 :         if( nBufferReadPos == mnCharsInBuffer )
     210             :         {
     211             :             // Already reached EOF? Then we can't read any more
     212          85 :             if( mbReachedEOF )
     213           0 :                 break;
     214             : 
     215             :             // No, so read new characters
     216          85 :             if( !implReadNext() )
     217           0 :                 break;
     218             :         }
     219             : 
     220             :         // Now there should be characters available
     221             :         // (otherwise the loop should have been breaked before)
     222       18110 :         sal_Unicode c = mpBuffer[ nBufferReadPos++ ];
     223             : 
     224       18110 :         if( bFindLineEnd )
     225             :         {
     226       15585 :             if( bFoundFirstLineEndChar )
     227             :             {
     228         493 :                 bFound = sal_True;
     229         493 :                 nCopyLen = nBufferReadPos - 2;
     230         493 :                 if( c == cLineEndChar1 || c == cLineEndChar2 )
     231             :                 {
     232             :                     // Same line end char -> new line break
     233         986 :                     if( c == cFirstLineEndChar )
     234             :                     {
     235           0 :                         nBufferReadPos--;
     236             :                     }
     237             :                 }
     238             :                 else
     239             :                 {
     240             :                     // No second line end char
     241           0 :                     nBufferReadPos--;
     242             :                 }
     243             :             }
     244       15092 :             else if( c == cLineEndChar1 || c == cLineEndChar2 )
     245             :             {
     246         493 :                 bFoundFirstLineEndChar = sal_True;
     247         493 :                 cFirstLineEndChar = c;
     248             :             }
     249             :         }
     250             :         else
     251             :         {
     252        5050 :             for( sal_Int32 i = 0 ; i < nDelimCount ; i++ )
     253             :             {
     254        2525 :                 if( c == pDelims[ i ] )
     255             :                 {
     256         130 :                     bFound = sal_True;
     257         130 :                     nCopyLen = nBufferReadPos;
     258         130 :                     if( bRemoveDelimiter )
     259           0 :                         nCopyLen--;
     260             :                 }
     261             :             }
     262             :         }
     263             :     }
     264             : 
     265             :     // Nothing found? Return all
     266         623 :     if( !nCopyLen && !bFound && mbReachedEOF )
     267           0 :         nCopyLen = nBufferReadPos;
     268             : 
     269             :     // Create string
     270         623 :     if( nCopyLen )
     271         587 :         aRetStr = OUString( mpBuffer, nCopyLen );
     272             : 
     273             :     // Copy rest of buffer
     274             :     memmove( mpBuffer, mpBuffer + nBufferReadPos,
     275         623 :         (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) );
     276         623 :     mnCharsInBuffer -= nBufferReadPos;
     277             : 
     278         623 :     return aRetStr;
     279             : }
     280             : 
     281             : 
     282          85 : sal_Int32 OTextInputStream::implReadNext()
     283             :         throw(IOException, RuntimeException)
     284             : {
     285          85 :     sal_Int32 nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
     286          85 :     if( nFreeBufferSize < READ_BYTE_COUNT )
     287          20 :         implResizeBuffer();
     288          85 :     nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
     289             : 
     290             :     try
     291             :     {
     292          85 :         sal_Int32 nBytesToRead = READ_BYTE_COUNT;
     293          85 :         sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, nBytesToRead );
     294          85 :         sal_Int32 nTotalRead = nRead;
     295          85 :         if( nRead < nBytesToRead )
     296          18 :             mbReachedEOF = sal_True;
     297             : 
     298             :         // Try to convert
     299             :         sal_uInt32 uiInfo;
     300          85 :         sal_Size nSrcCvtBytes = 0;
     301          85 :         sal_Size nTargetCount = 0;
     302          85 :         sal_Size nSourceCount = 0;
     303           0 :         while( sal_True )
     304             :         {
     305          85 :             const sal_Int8 *pbSource = mSeqSource.getConstArray();
     306             : 
     307             :             // All invalid characters are transformed to the unicode undefined char
     308             :             nTargetCount += rtl_convertTextToUnicode(
     309             :                                 mConvText2Unicode,
     310             :                                 mContextText2Unicode,
     311             :                                 (const sal_Char*) &( pbSource[nSourceCount] ),
     312             :                                 nTotalRead - nSourceCount,
     313          85 :                                 mpBuffer + mnCharsInBuffer + nTargetCount,
     314             :                                 nFreeBufferSize - nTargetCount,
     315             :                                 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT   |
     316             :                                 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
     317             :                                 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
     318             :                                 &uiInfo,
     319         170 :                                 &nSrcCvtBytes );
     320          85 :             nSourceCount += nSrcCvtBytes;
     321             : 
     322          85 :             sal_Bool bCont = sal_False;
     323          85 :             if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL )
     324             :             {
     325           0 :                 implResizeBuffer();
     326           0 :                 bCont = sal_True;
     327             :             }
     328             : 
     329          85 :             if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL )
     330             :             {
     331             :                 // read next byte
     332           0 :                 static Sequence< sal_Int8 > aOneByteSeq( 1 );
     333           0 :                 nRead = mxStream->readSomeBytes( aOneByteSeq, 1 );
     334           0 :                 if( nRead == 0 )
     335             :                 {
     336           0 :                     mbReachedEOF = sal_True;
     337           0 :                     break;
     338             :                 }
     339             : 
     340           0 :                 sal_Int32 nOldLen = mSeqSource.getLength();
     341           0 :                 nTotalRead++;
     342           0 :                 if( nTotalRead > nOldLen )
     343             :                 {
     344           0 :                     mSeqSource.realloc( nTotalRead );
     345             :                 }
     346           0 :                 mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ];
     347           0 :                 pbSource = mSeqSource.getConstArray();
     348           0 :                 bCont = sal_True;
     349             :             }
     350             : 
     351          85 :             if( bCont )
     352           0 :                 continue;
     353          85 :             break;
     354             :         }
     355             : 
     356          85 :         mnCharsInBuffer += nTargetCount;
     357          85 :         return nTargetCount;
     358             :     }
     359           0 :     catch( NotConnectedException& )
     360             :     {
     361           0 :         throw IOException();
     362             :         //throw IOException( L"OTextInputStream::implReadString failed" );
     363             :     }
     364           0 :     catch( BufferSizeExceededException& )
     365             :     {
     366           0 :         throw IOException();
     367             :     }
     368             : }
     369             : 
     370          20 : void OTextInputStream::setEncoding( const OUString& Encoding )
     371             :     throw(RuntimeException)
     372             : {
     373          20 :     OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
     374          20 :     rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
     375          20 :     if( RTL_TEXTENCODING_DONTKNOW == encoding )
     376          20 :         return;
     377             : 
     378          20 :     mbEncodingInitialized = true;
     379          20 :     mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
     380          20 :     mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
     381          20 :     mEncoding = Encoding;
     382             : }
     383             : 
     384             : //===========================================================================
     385             : // XInputStream
     386             : 
     387           0 : sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
     388             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
     389             : {
     390           0 :     return mxStream->readBytes( aData, nBytesToRead );
     391             : }
     392             : 
     393           0 : sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
     394             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
     395             : {
     396           0 :     return mxStream->readSomeBytes( aData, nMaxBytesToRead );
     397             : }
     398             : 
     399           0 : void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
     400             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
     401             : {
     402           0 :     mxStream->skipBytes( nBytesToSkip );
     403           0 : }
     404             : 
     405           0 : sal_Int32 OTextInputStream::available(  )
     406             :     throw(NotConnectedException, IOException, RuntimeException)
     407             : {
     408           0 :     return mxStream->available();
     409             : }
     410             : 
     411           0 : void OTextInputStream::closeInput(  )
     412             :     throw(NotConnectedException, IOException, RuntimeException)
     413             : {
     414           0 :     mxStream->closeInput();
     415           0 : }
     416             : 
     417             : 
     418             : //===========================================================================
     419             : // XActiveDataSink
     420             : 
     421          20 : void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
     422             :     throw(RuntimeException)
     423             : {
     424          20 :     mxStream = aStream;
     425          20 : }
     426             : 
     427           0 : Reference< XInputStream > OTextInputStream::getInputStream()
     428             :     throw(RuntimeException)
     429             : {
     430           0 :     return mxStream;
     431             : }
     432             : 
     433             : 
     434          20 : Reference< XInterface > SAL_CALL TextInputStream_CreateInstance(
     435             :     SAL_UNUSED_PARAMETER const Reference< XComponentContext > &)
     436             : {
     437          20 :     return Reference < XInterface >( ( OWeakObject * ) new OTextInputStream() );
     438             : }
     439             : 
     440           2 : OUString TextInputStream_getImplementationName()
     441             : {
     442           2 :     return OUString ( IMPLEMENTATION_NAME );
     443             : }
     444             : 
     445           2 : Sequence< OUString > TextInputStream_getSupportedServiceNames()
     446             : {
     447           2 :     Sequence< OUString > seqNames(1);
     448           2 :     seqNames.getArray()[0] = SERVICE_NAME;
     449           2 :     return seqNames;
     450             : }
     451             : 
     452           0 : OUString OTextInputStream::getImplementationName() throw()
     453             : {
     454           0 :     return TextInputStream_getImplementationName();
     455             : }
     456             : 
     457           0 : sal_Bool OTextInputStream::supportsService(const OUString& ServiceName) throw()
     458             : {
     459           0 :     Sequence< OUString > aSNL = getSupportedServiceNames();
     460           0 :     const OUString * pArray = aSNL.getConstArray();
     461             : 
     462           0 :     for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
     463           0 :         if( pArray[i] == ServiceName )
     464           0 :             return sal_True;
     465             : 
     466           0 :     return sal_False;
     467             : }
     468             : 
     469           0 : Sequence< OUString > OTextInputStream::getSupportedServiceNames(void) throw()
     470             : {
     471           0 :     return TextInputStream_getSupportedServiceNames();
     472             : }
     473             : 
     474             : }
     475             : 
     476             : using namespace io_TextInputStream;
     477             : 
     478             : static struct ImplementationEntry g_entries[] =
     479             : {
     480             :     {
     481             :         TextInputStream_CreateInstance, TextInputStream_getImplementationName ,
     482             :         TextInputStream_getSupportedServiceNames, createSingleComponentFactory ,
     483             :         &g_moduleCount.modCnt , 0
     484             :     },
     485             :     { 0, 0, 0, 0, 0, 0 }
     486             : };
     487             : 
     488             : extern "C"
     489             : {
     490           0 : SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
     491             : {
     492           0 :     return g_moduleCount.canUnload( &g_moduleCount , pTime );
     493             : }
     494             : 
     495             : //==================================================================================================
     496           2 : SAL_DLLPUBLIC_EXPORT void * SAL_CALL textinstream_component_getFactory(
     497             :     const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
     498             : {
     499           2 :     return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
     500             : }
     501             : }
     502             : 
     503             : 
     504             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10