LCOV - code coverage report
Current view: top level - io/source/TextInputStream - TextInputStream.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 112 160 70.0 %
Date: 2014-04-11 Functions: 14 23 60.9 %
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 <uno/mapping.hxx>
      24             : 
      25             : #include <cppuhelper/factory.hxx>
      26             : #include <cppuhelper/implbase2.hxx>
      27             : #include <cppuhelper/implementationentry.hxx>
      28             : #include <cppuhelper/supportsservice.hxx>
      29             : 
      30             : #include <rtl/textenc.h>
      31             : #include <rtl/tencinfo.h>
      32             : 
      33             : #include <com/sun/star/io/XTextInputStream2.hpp>
      34             : #include <com/sun/star/lang/XServiceInfo.hpp>
      35             : 
      36             : #include "services.hxx"
      37             : 
      38             : #define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
      39             : #define SERVICE_NAME "com.sun.star.io.TextInputStream"
      40             : 
      41             : using namespace ::osl;
      42             : using namespace ::rtl;
      43             : using namespace ::cppu;
      44             : using namespace ::com::sun::star::uno;
      45             : using namespace ::com::sun::star::lang;
      46             : using namespace ::com::sun::star::io;
      47             : using namespace ::com::sun::star::registry;
      48             : 
      49             : namespace io_TextInputStream
      50             : {
      51             : 
      52             : // Implementation XTextInputStream
      53             : 
      54             : typedef WeakImplHelper2< XTextInputStream2, XServiceInfo > TextInputStreamHelper;
      55             : 
      56             : #define INITIAL_UNICODE_BUFFER_CAPACITY     0x100
      57             : #define READ_BYTE_COUNT                     0x100
      58             : 
      59             : class OTextInputStream : public TextInputStreamHelper
      60             : {
      61             :     Reference< XInputStream > mxStream;
      62             : 
      63             :     // Encoding
      64             :     OUString mEncoding;
      65             :     sal_Bool mbEncodingInitialized;
      66             :     rtl_TextToUnicodeConverter  mConvText2Unicode;
      67             :     rtl_TextToUnicodeContext    mContextText2Unicode;
      68             :     Sequence<sal_Int8>          mSeqSource;
      69             : 
      70             :     // Internal buffer for characters that are already converted successfully
      71             :     sal_Unicode* mpBuffer;
      72             :     sal_Int32 mnBufferSize;
      73             :     sal_Int32 mnCharsInBuffer;
      74             :     sal_Bool mbReachedEOF;
      75             : 
      76             :     void implResizeBuffer( void );
      77             :     OUString implReadString( const Sequence< sal_Unicode >& Delimiters,
      78             :         sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
      79             :             throw(IOException, RuntimeException);
      80             :     sal_Int32 implReadNext() throw(IOException, RuntimeException);
      81             : 
      82             : public:
      83             :     OTextInputStream();
      84             :     virtual ~OTextInputStream();
      85             : 
      86             :     // Methods XTextInputStream
      87             :     virtual OUString SAL_CALL readLine(  )
      88             :         throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
      89             :     virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
      90             :         throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
      91             :     virtual sal_Bool SAL_CALL isEOF(  )
      92             :         throw(IOException, RuntimeException, std::exception) SAL_OVERRIDE;
      93             :     virtual void SAL_CALL setEncoding( const OUString& Encoding ) throw(RuntimeException, std::exception) SAL_OVERRIDE;
      94             : 
      95             :     // Methods XInputStream
      96             :     virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
      97             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
      98             :     virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
      99             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     100             :     virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
     101             :         throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     102             :     virtual sal_Int32 SAL_CALL available(  )
     103             :         throw(NotConnectedException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     104             :     virtual void SAL_CALL closeInput(  )
     105             :         throw(NotConnectedException, IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     106             : 
     107             :     // Methods XActiveDataSink
     108             :     virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream )
     109             :         throw(RuntimeException, std::exception) SAL_OVERRIDE;
     110             :     virtual Reference< XInputStream > SAL_CALL getInputStream()
     111             :         throw(RuntimeException, std::exception) SAL_OVERRIDE;
     112             : 
     113             :     // Methods XServiceInfo
     114             :         virtual OUString              SAL_CALL getImplementationName() throw(std::exception) SAL_OVERRIDE;
     115             :         virtual Sequence< OUString >  SAL_CALL getSupportedServiceNames(void) throw(std::exception) SAL_OVERRIDE;
     116             :         virtual sal_Bool              SAL_CALL supportsService(const OUString& ServiceName) throw(std::exception) SAL_OVERRIDE;
     117             : };
     118             : 
     119         179 : OTextInputStream::OTextInputStream()
     120             :     : mbEncodingInitialized(false)
     121             :     , mConvText2Unicode(NULL)
     122             :     , mContextText2Unicode(NULL)
     123             :     , mSeqSource(READ_BYTE_COUNT)
     124             :     , mpBuffer(NULL)
     125             :     , mnBufferSize(0)
     126             :     , mnCharsInBuffer(0)
     127         179 :     , mbReachedEOF(sal_False)
     128             : {
     129         179 : }
     130             : 
     131         537 : OTextInputStream::~OTextInputStream()
     132             : {
     133         179 :     if( mbEncodingInitialized )
     134             :     {
     135         178 :         rtl_destroyUnicodeToTextContext( mConvText2Unicode, mContextText2Unicode );
     136         178 :         rtl_destroyUnicodeToTextConverter( mConvText2Unicode );
     137             :     }
     138             : 
     139         179 :     delete[] mpBuffer;
     140         358 : }
     141             : 
     142         176 : void OTextInputStream::implResizeBuffer( void )
     143             : {
     144         176 :     sal_Int32 mnNewBufferSize = mnBufferSize * 2;
     145         176 :     sal_Unicode* pNewBuffer = new sal_Unicode[ mnNewBufferSize ];
     146         176 :     memcpy( pNewBuffer, mpBuffer, mnCharsInBuffer * sizeof( sal_Unicode ) );
     147         176 :     delete[] mpBuffer;
     148         176 :     mpBuffer = pNewBuffer;
     149         176 :     mnBufferSize = mnNewBufferSize;
     150         176 : }
     151             : 
     152             : 
     153             : 
     154             : // XTextInputStream
     155             : 
     156        7086 : OUString OTextInputStream::readLine(  )
     157             :     throw(IOException, RuntimeException, std::exception)
     158             : {
     159        7086 :     static Sequence< sal_Unicode > aDummySeq;
     160        7086 :     return implReadString( aDummySeq, sal_True, sal_True );
     161             : }
     162             : 
     163         154 : OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
     164             :         throw(IOException, RuntimeException, std::exception)
     165             : {
     166         154 :     return implReadString( Delimiters, bRemoveDelimiter, sal_False );
     167             : }
     168             : 
     169        7467 : sal_Bool OTextInputStream::isEOF()
     170             :     throw(IOException, RuntimeException, std::exception)
     171             : {
     172        7467 :     sal_Bool bRet = sal_False;
     173        7467 :     if( mnCharsInBuffer == 0 && mbReachedEOF )
     174         150 :         bRet = sal_True;
     175        7467 :     return bRet;
     176             : }
     177             : 
     178             : 
     179        7240 : OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters,
     180             :                                            sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
     181             :         throw(IOException, RuntimeException)
     182             : {
     183        7240 :     OUString aRetStr;
     184        7240 :     if( !mbEncodingInitialized )
     185             :     {
     186           0 :         OUString aUtf8Str("utf8");
     187           0 :         setEncoding( aUtf8Str );
     188             :     }
     189        7240 :     if( !mbEncodingInitialized )
     190           0 :         return aRetStr;
     191             : 
     192        7240 :     if( !mpBuffer )
     193             :     {
     194         178 :         mnBufferSize = INITIAL_UNICODE_BUFFER_CAPACITY;
     195         178 :         mpBuffer = new sal_Unicode[ mnBufferSize ];
     196             :     }
     197             : 
     198             :     // Only for bFindLineEnd
     199        7240 :     sal_Unicode cLineEndChar1 = 0x0D;
     200        7240 :     sal_Unicode cLineEndChar2 = 0x0A;
     201             : 
     202        7240 :     sal_Int32 nBufferReadPos = 0;
     203        7240 :     sal_Int32 nCopyLen = 0;
     204        7240 :     sal_Bool bFound = sal_False;
     205        7240 :     sal_Bool bFoundFirstLineEndChar = sal_False;
     206        7240 :     sal_Unicode cFirstLineEndChar = 0;
     207        7240 :     const sal_Unicode* pDelims = Delimiters.getConstArray();
     208        7240 :     const sal_Int32 nDelimCount = Delimiters.getLength();
     209      277266 :     while( !bFound )
     210             :     {
     211             :         // Still characters available?
     212      262786 :         if( nBufferReadPos == mnCharsInBuffer )
     213             :         {
     214             :             // Already reached EOF? Then we can't read any more
     215        1145 :             if( mbReachedEOF )
     216           0 :                 break;
     217             : 
     218             :             // No, so read new characters
     219        1145 :             if( !implReadNext() )
     220           0 :                 break;
     221             :         }
     222             : 
     223             :         // Now there should be characters available
     224             :         // (otherwise the loop should have been breaked before)
     225      262786 :         sal_Unicode c = mpBuffer[ nBufferReadPos++ ];
     226             : 
     227      262786 :         if( bFindLineEnd )
     228             :         {
     229      259574 :             if( bFoundFirstLineEndChar )
     230             :             {
     231        7086 :                 bFound = sal_True;
     232        7086 :                 nCopyLen = nBufferReadPos - 2;
     233        7086 :                 if( c == cLineEndChar1 || c == cLineEndChar2 )
     234             :                 {
     235             :                     // Same line end char -> new line break
     236       14172 :                     if( c == cFirstLineEndChar )
     237             :                     {
     238           0 :                         nBufferReadPos--;
     239             :                     }
     240             :                 }
     241             :                 else
     242             :                 {
     243             :                     // No second line end char
     244           0 :                     nBufferReadPos--;
     245             :                 }
     246             :             }
     247      252488 :             else if( c == cLineEndChar1 || c == cLineEndChar2 )
     248             :             {
     249        7086 :                 bFoundFirstLineEndChar = sal_True;
     250        7086 :                 cFirstLineEndChar = c;
     251             :             }
     252             :         }
     253             :         else
     254             :         {
     255        6424 :             for( sal_Int32 i = 0 ; i < nDelimCount ; i++ )
     256             :             {
     257        3212 :                 if( c == pDelims[ i ] )
     258             :                 {
     259         154 :                     bFound = sal_True;
     260         154 :                     nCopyLen = nBufferReadPos;
     261         154 :                     if( bRemoveDelimiter )
     262           0 :                         nCopyLen--;
     263             :                 }
     264             :             }
     265             :         }
     266             :     }
     267             : 
     268             :     // Nothing found? Return all
     269        7240 :     if( !nCopyLen && !bFound && mbReachedEOF )
     270           0 :         nCopyLen = nBufferReadPos;
     271             : 
     272             :     // Create string
     273        7240 :     if( nCopyLen )
     274        6597 :         aRetStr = OUString( mpBuffer, nCopyLen );
     275             : 
     276             :     // Copy rest of buffer
     277             :     memmove( mpBuffer, mpBuffer + nBufferReadPos,
     278        7240 :         (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) );
     279        7240 :     mnCharsInBuffer -= nBufferReadPos;
     280             : 
     281        7240 :     return aRetStr;
     282             : }
     283             : 
     284             : 
     285        1145 : sal_Int32 OTextInputStream::implReadNext()
     286             :         throw(IOException, RuntimeException)
     287             : {
     288        1145 :     sal_Int32 nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
     289        1145 :     if( nFreeBufferSize < READ_BYTE_COUNT )
     290         176 :         implResizeBuffer();
     291        1145 :     nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
     292             : 
     293             :     try
     294             :     {
     295        1145 :         sal_Int32 nBytesToRead = READ_BYTE_COUNT;
     296        1145 :         sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, nBytesToRead );
     297        1145 :         sal_Int32 nTotalRead = nRead;
     298        1145 :         if( nRead < nBytesToRead )
     299         151 :             mbReachedEOF = sal_True;
     300             : 
     301             :         // Try to convert
     302             :         sal_uInt32 uiInfo;
     303        1145 :         sal_Size nSrcCvtBytes = 0;
     304        1145 :         sal_Size nTargetCount = 0;
     305        1145 :         sal_Size nSourceCount = 0;
     306             :         while( true )
     307             :         {
     308        1145 :             const sal_Int8 *pbSource = mSeqSource.getConstArray();
     309             : 
     310             :             // All invalid characters are transformed to the unicode undefined char
     311             :             nTargetCount += rtl_convertTextToUnicode(
     312             :                                 mConvText2Unicode,
     313             :                                 mContextText2Unicode,
     314             :                                 (const sal_Char*) &( pbSource[nSourceCount] ),
     315             :                                 nTotalRead - nSourceCount,
     316        1145 :                                 mpBuffer + mnCharsInBuffer + nTargetCount,
     317             :                                 nFreeBufferSize - nTargetCount,
     318             :                                 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT   |
     319             :                                 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
     320             :                                 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
     321             :                                 &uiInfo,
     322        2290 :                                 &nSrcCvtBytes );
     323        1145 :             nSourceCount += nSrcCvtBytes;
     324             : 
     325        1145 :             sal_Bool bCont = sal_False;
     326        1145 :             if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL )
     327             :             {
     328           0 :                 implResizeBuffer();
     329           0 :                 bCont = sal_True;
     330             :             }
     331             : 
     332        1145 :             if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL )
     333             :             {
     334             :                 // read next byte
     335           0 :                 static Sequence< sal_Int8 > aOneByteSeq( 1 );
     336           0 :                 nRead = mxStream->readSomeBytes( aOneByteSeq, 1 );
     337           0 :                 if( nRead == 0 )
     338             :                 {
     339           0 :                     mbReachedEOF = sal_True;
     340           0 :                     break;
     341             :                 }
     342             : 
     343           0 :                 sal_Int32 nOldLen = mSeqSource.getLength();
     344           0 :                 nTotalRead++;
     345           0 :                 if( nTotalRead > nOldLen )
     346             :                 {
     347           0 :                     mSeqSource.realloc( nTotalRead );
     348             :                 }
     349           0 :                 mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ];
     350           0 :                 pbSource = mSeqSource.getConstArray();
     351           0 :                 bCont = sal_True;
     352             :             }
     353             : 
     354        1145 :             if( bCont )
     355           0 :                 continue;
     356        1145 :             break;
     357             :         }
     358             : 
     359        1145 :         mnCharsInBuffer += nTargetCount;
     360        1145 :         return nTargetCount;
     361             :     }
     362           0 :     catch( NotConnectedException& )
     363             :     {
     364           0 :         throw IOException();
     365             :         //throw IOException( L"OTextInputStream::implReadString failed" );
     366             :     }
     367           0 :     catch( BufferSizeExceededException& )
     368             :     {
     369           0 :         throw IOException();
     370             :     }
     371             : }
     372             : 
     373         178 : void OTextInputStream::setEncoding( const OUString& Encoding )
     374             :     throw(RuntimeException, std::exception)
     375             : {
     376         178 :     OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
     377         178 :     rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
     378         178 :     if( RTL_TEXTENCODING_DONTKNOW == encoding )
     379         178 :         return;
     380             : 
     381         178 :     mbEncodingInitialized = true;
     382         178 :     mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
     383         178 :     mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
     384         178 :     mEncoding = Encoding;
     385             : }
     386             : 
     387             : 
     388             : // XInputStream
     389             : 
     390           0 : sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
     391             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
     392             : {
     393           0 :     return mxStream->readBytes( aData, nBytesToRead );
     394             : }
     395             : 
     396           0 : sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
     397             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
     398             : {
     399           0 :     return mxStream->readSomeBytes( aData, nMaxBytesToRead );
     400             : }
     401             : 
     402           0 : void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
     403             :     throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
     404             : {
     405           0 :     mxStream->skipBytes( nBytesToSkip );
     406           0 : }
     407             : 
     408           0 : sal_Int32 OTextInputStream::available(  )
     409             :     throw(NotConnectedException, IOException, RuntimeException, std::exception)
     410             : {
     411           0 :     return mxStream->available();
     412             : }
     413             : 
     414           0 : void OTextInputStream::closeInput(  )
     415             :     throw(NotConnectedException, IOException, RuntimeException, std::exception)
     416             : {
     417           0 :     mxStream->closeInput();
     418           0 : }
     419             : 
     420             : 
     421             : 
     422             : // XActiveDataSink
     423             : 
     424         178 : void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
     425             :     throw(RuntimeException, std::exception)
     426             : {
     427         178 :     mxStream = aStream;
     428         178 : }
     429             : 
     430           0 : Reference< XInputStream > OTextInputStream::getInputStream()
     431             :     throw(RuntimeException, std::exception)
     432             : {
     433           0 :     return mxStream;
     434             : }
     435             : 
     436             : 
     437         179 : Reference< XInterface > SAL_CALL TextInputStream_CreateInstance(
     438             :     SAL_UNUSED_PARAMETER const Reference< XComponentContext > &)
     439             : {
     440         179 :     return Reference < XInterface >( ( OWeakObject * ) new OTextInputStream() );
     441             : }
     442             : 
     443         103 : OUString TextInputStream_getImplementationName()
     444             : {
     445         103 :     return OUString ( IMPLEMENTATION_NAME );
     446             : }
     447             : 
     448           5 : Sequence< OUString > TextInputStream_getSupportedServiceNames()
     449             : {
     450           5 :     Sequence< OUString > seqNames(1);
     451           5 :     seqNames.getArray()[0] = SERVICE_NAME;
     452           5 :     return seqNames;
     453             : }
     454             : 
     455           0 : OUString OTextInputStream::getImplementationName() throw(std::exception)
     456             : {
     457           0 :     return TextInputStream_getImplementationName();
     458             : }
     459             : 
     460           0 : sal_Bool OTextInputStream::supportsService(const OUString& ServiceName) throw(std::exception)
     461             : {
     462           0 :     return cppu::supportsService(this, ServiceName);
     463             : }
     464             : 
     465           0 : Sequence< OUString > OTextInputStream::getSupportedServiceNames(void) throw(std::exception)
     466             : {
     467           0 :     return TextInputStream_getSupportedServiceNames();
     468             : }
     469             : 
     470             : }
     471             : 
     472             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10