summaryrefslogtreecommitdiff
path: root/io/source/TextInputStream/TextInputStream.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'io/source/TextInputStream/TextInputStream.cxx')
-rw-r--r--io/source/TextInputStream/TextInputStream.cxx537
1 files changed, 537 insertions, 0 deletions
diff --git a/io/source/TextInputStream/TextInputStream.cxx b/io/source/TextInputStream/TextInputStream.cxx
new file mode 100644
index 000000000000..1c891f1b839e
--- /dev/null
+++ b/io/source/TextInputStream/TextInputStream.cxx
@@ -0,0 +1,537 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_io.hxx"
+
+
+#include <string.h>
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+
+#include <rtl/unload.h>
+
+#include <uno/mapping.hxx>
+
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/implementationentry.hxx>
+
+#include <rtl/textenc.h>
+#include <rtl/tencinfo.h>
+
+#include <com/sun/star/io/XTextInputStream.hpp>
+#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+
+#define IMPLEMENTATION_NAME "com.sun.star.comp.io.TextInputStream"
+#define SERVICE_NAME "com.sun.star.io.TextInputStream"
+
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::registry;
+
+namespace io_TextInputStream
+{
+ rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;
+
+//===========================================================================
+// Implementation XTextInputStream
+
+typedef WeakImplHelper3< XTextInputStream, XActiveDataSink, XServiceInfo > TextInputStreamHelper;
+class OCommandEnvironment;
+
+#define INITIAL_UNICODE_BUFFER_CAPACITY 0x100
+#define READ_BYTE_COUNT 0x100
+
+class OTextInputStream : public TextInputStreamHelper
+{
+ Reference< XInputStream > mxStream;
+
+ // Encoding
+ OUString mEncoding;
+ sal_Bool mbEncodingInitialized;
+ rtl_TextToUnicodeConverter mConvText2Unicode;
+ rtl_TextToUnicodeContext mContextText2Unicode;
+ Sequence<sal_Int8> mSeqSource;
+
+ // Internal buffer for characters that are already converted successfully
+ sal_Unicode* mpBuffer;
+ sal_Int32 mnBufferSize;
+ sal_Int32 mnCharsInBuffer;
+ sal_Bool mbReachedEOF;
+
+ void implResizeBuffer( void );
+ OUString implReadString( const Sequence< sal_Unicode >& Delimiters,
+ sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
+ throw(IOException, RuntimeException);
+ sal_Int32 implReadNext() throw(IOException, RuntimeException);
+
+public:
+ OTextInputStream();
+ virtual ~OTextInputStream();
+
+ // Methods XTextInputStream
+ virtual OUString SAL_CALL readLine( )
+ throw(IOException, RuntimeException);
+ virtual OUString SAL_CALL readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool bRemoveDelimiter )
+ throw(IOException, RuntimeException);
+ virtual sal_Bool SAL_CALL isEOF( )
+ throw(IOException, RuntimeException);
+ virtual void SAL_CALL setEncoding( const OUString& Encoding ) throw(RuntimeException);
+
+ // Methods XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
+ virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException);
+ virtual sal_Int32 SAL_CALL available( )
+ throw(NotConnectedException, IOException, RuntimeException);
+ virtual void SAL_CALL closeInput( )
+ throw(NotConnectedException, IOException, RuntimeException);
+
+ // Methods XActiveDataSink
+ virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream )
+ throw(RuntimeException);
+ virtual Reference< XInputStream > SAL_CALL getInputStream()
+ throw(RuntimeException);
+
+ // Methods XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() throw();
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw();
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw();
+};
+
+OTextInputStream::OTextInputStream()
+ : mSeqSource( READ_BYTE_COUNT ), mpBuffer( NULL ), mnBufferSize( 0 )
+ , mnCharsInBuffer( 0 ), mbReachedEOF( sal_False )
+{
+ g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
+ mbEncodingInitialized = false;
+}
+
+OTextInputStream::~OTextInputStream()
+{
+ if( mbEncodingInitialized )
+ {
+ rtl_destroyUnicodeToTextContext( mConvText2Unicode, mContextText2Unicode );
+ rtl_destroyUnicodeToTextConverter( mConvText2Unicode );
+ }
+ g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
+}
+
+void OTextInputStream::implResizeBuffer( void )
+{
+ sal_Int32 mnNewBufferSize = mnBufferSize * 2;
+ sal_Unicode* pNewBuffer = new sal_Unicode[ mnNewBufferSize ];
+ memcpy( pNewBuffer, mpBuffer, mnCharsInBuffer * sizeof( sal_Unicode ) );
+ mpBuffer = pNewBuffer;
+ mnBufferSize = mnNewBufferSize;
+}
+
+
+//===========================================================================
+// XTextInputStream
+
+OUString OTextInputStream::readLine( )
+ throw(IOException, RuntimeException)
+{
+ static Sequence< sal_Unicode > aDummySeq;
+ return implReadString( aDummySeq, sal_True, sal_True );
+}
+
+OUString OTextInputStream::readString( const Sequence< sal_Unicode >& Delimiters, sal_Bool )
+ throw(IOException, RuntimeException)
+{
+ return implReadString( Delimiters, sal_True, sal_False );
+}
+
+sal_Bool OTextInputStream::isEOF()
+ throw(IOException, RuntimeException)
+{
+ sal_Bool bRet = sal_False;
+ if( mnCharsInBuffer == 0 && mbReachedEOF )
+ bRet = sal_True;
+ return bRet;
+}
+
+
+OUString OTextInputStream::implReadString( const Sequence< sal_Unicode >& Delimiters,
+ sal_Bool bRemoveDelimiter, sal_Bool bFindLineEnd )
+ throw(IOException, RuntimeException)
+{
+ OUString aRetStr;
+ if( !mbEncodingInitialized )
+ {
+ OUString aUtf8Str( RTL_CONSTASCII_USTRINGPARAM("utf8") );
+ setEncoding( aUtf8Str );
+ }
+ if( !mbEncodingInitialized )
+ return aRetStr;
+
+ if( !mpBuffer )
+ {
+ mnBufferSize = INITIAL_UNICODE_BUFFER_CAPACITY;
+ mpBuffer = new sal_Unicode[ mnBufferSize ];
+ }
+
+ // Only for bFindLineEnd
+ sal_Unicode cLineEndChar1 = 0x0D;
+ sal_Unicode cLineEndChar2 = 0x0A;
+
+ sal_Int32 nBufferReadPos = 0;
+ sal_Int32 nCopyLen = 0;
+ sal_Bool bFound = sal_False;
+ sal_Bool bFoundFirstLineEndChar = sal_False;
+ sal_Unicode cFirstLineEndChar = 0;
+ const sal_Unicode* pDelims = Delimiters.getConstArray();
+ const sal_Int32 nDelimCount = Delimiters.getLength();
+ while( !bFound )
+ {
+ // Still characters available?
+ if( nBufferReadPos == mnCharsInBuffer )
+ {
+ // Already reached EOF? Then we can't read any more
+ if( mbReachedEOF )
+ break;
+
+ // No, so read new characters
+ if( !implReadNext() )
+ break;
+ }
+
+ // Now there should be characters available
+ // (otherwise the loop should have been breaked before)
+ sal_Unicode c = mpBuffer[ nBufferReadPos++ ];
+
+ if( bFindLineEnd )
+ {
+ if( bFoundFirstLineEndChar )
+ {
+ bFound = sal_True;
+ nCopyLen = nBufferReadPos - 2;
+ if( c == cLineEndChar1 || c == cLineEndChar2 )
+ {
+ // Same line end char -> new line break
+ if( c == cFirstLineEndChar )
+ {
+ nBufferReadPos--;
+ }
+ }
+ else
+ {
+ // No second line end char
+ nBufferReadPos--;
+ }
+ }
+ else if( c == cLineEndChar1 || c == cLineEndChar2 )
+ {
+ bFoundFirstLineEndChar = sal_True;
+ cFirstLineEndChar = c;
+ }
+ }
+ else
+ {
+ for( sal_Int32 i = 0 ; i < nDelimCount ; i++ )
+ {
+ if( c == pDelims[ i ] )
+ {
+ bFound = sal_True;
+ nCopyLen = nBufferReadPos;
+ if( bRemoveDelimiter )
+ nCopyLen--;
+ }
+ }
+ }
+ }
+
+ // Nothing found? Return all
+ if( !nCopyLen && !bFound && mbReachedEOF )
+ nCopyLen = nBufferReadPos;
+
+ // Create string
+ if( nCopyLen )
+ aRetStr = OUString( mpBuffer, nCopyLen );
+
+ // Copy rest of buffer
+ memmove( mpBuffer, mpBuffer + nBufferReadPos,
+ (mnCharsInBuffer - nBufferReadPos) * sizeof( sal_Unicode ) );
+ mnCharsInBuffer -= nBufferReadPos;
+
+ return aRetStr;
+}
+
+
+sal_Int32 OTextInputStream::implReadNext()
+ throw(IOException, RuntimeException)
+{
+ sal_Int32 nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
+ if( nFreeBufferSize < READ_BYTE_COUNT )
+ implResizeBuffer();
+ nFreeBufferSize = mnBufferSize - mnCharsInBuffer;
+
+ try
+ {
+ sal_Int32 nBytesToRead = READ_BYTE_COUNT;
+ sal_Int32 nRead = mxStream->readSomeBytes( mSeqSource, nBytesToRead );
+ sal_Int32 nTotalRead = nRead;
+ if( nRead < nBytesToRead )
+ mbReachedEOF = sal_True;
+
+ // Try to convert
+ sal_uInt32 uiInfo;
+ sal_Size nSrcCvtBytes = 0;
+ sal_Size nTargetCount = 0;
+ sal_Size nSourceCount = 0;
+ while( sal_True )
+ {
+ const sal_Int8 *pbSource = mSeqSource.getConstArray();
+
+ // All invalid characters are transformed to the unicode undefined char
+ nTargetCount += rtl_convertTextToUnicode(
+ mConvText2Unicode,
+ mContextText2Unicode,
+ (const sal_Char*) &( pbSource[nSourceCount] ),
+ nTotalRead - nSourceCount,
+ mpBuffer + mnCharsInBuffer + nTargetCount,
+ nFreeBufferSize - nTargetCount,
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT,
+ &uiInfo,
+ &nSrcCvtBytes );
+ nSourceCount += nSrcCvtBytes;
+
+ sal_Bool bCont = sal_False;
+ if( uiInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL )
+ {
+ implResizeBuffer();
+ bCont = sal_True;
+ }
+
+ if( uiInfo & RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL )
+ {
+ // read next byte
+ static Sequence< sal_Int8 > aOneByteSeq( 1 );
+ nRead = mxStream->readSomeBytes( aOneByteSeq, 1 );
+ if( nRead == 0 )
+ {
+ mbReachedEOF = sal_True;
+ break;
+ }
+
+ sal_Int32 nOldLen = mSeqSource.getLength();
+ nTotalRead++;
+ if( nTotalRead > nOldLen )
+ {
+ mSeqSource.realloc( nTotalRead );
+ }
+ mSeqSource.getArray()[ nOldLen ] = aOneByteSeq.getConstArray()[ 0 ];
+ pbSource = mSeqSource.getConstArray();
+ bCont = sal_True;
+ }
+
+ if( bCont )
+ continue;
+ break;
+ }
+
+ mnCharsInBuffer += nTargetCount;
+ return nTargetCount;
+ }
+ catch( NotConnectedException& )
+ {
+ throw IOException();
+ //throw IOException( L"OTextInputStream::implReadString failed" );
+ }
+ catch( BufferSizeExceededException& )
+ {
+ throw IOException();
+ }
+}
+
+void OTextInputStream::setEncoding( const OUString& Encoding )
+ throw(RuntimeException)
+{
+ OString aOEncodingStr = OUStringToOString( Encoding, RTL_TEXTENCODING_ASCII_US );
+ rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( aOEncodingStr.getStr() );
+ if( RTL_TEXTENCODING_DONTKNOW == encoding )
+ return;
+
+ mbEncodingInitialized = true;
+ mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
+ mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
+ mEncoding = Encoding;
+}
+
+//===========================================================================
+// XInputStream
+
+sal_Int32 OTextInputStream::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ return mxStream->readBytes( aData, nBytesToRead );
+}
+
+sal_Int32 OTextInputStream::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ return mxStream->readSomeBytes( aData, nMaxBytesToRead );
+}
+
+void OTextInputStream::skipBytes( sal_Int32 nBytesToSkip )
+ throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
+{
+ mxStream->skipBytes( nBytesToSkip );
+}
+
+sal_Int32 OTextInputStream::available( )
+ throw(NotConnectedException, IOException, RuntimeException)
+{
+ return mxStream->available();
+}
+
+void OTextInputStream::closeInput( )
+ throw(NotConnectedException, IOException, RuntimeException)
+{
+ mxStream->closeInput();
+}
+
+
+//===========================================================================
+// XActiveDataSink
+
+void OTextInputStream::setInputStream( const Reference< XInputStream >& aStream )
+ throw(RuntimeException)
+{
+ mxStream = aStream;
+}
+
+Reference< XInputStream > OTextInputStream::getInputStream()
+ throw(RuntimeException)
+{
+ return mxStream;
+}
+
+
+Reference< XInterface > SAL_CALL TextInputStream_CreateInstance( const Reference< XComponentContext > &)
+{
+ return Reference < XInterface >( ( OWeakObject * ) new OTextInputStream() );
+}
+
+OUString TextInputStream_getImplementationName()
+{
+ return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPLEMENTATION_NAME ) );
+}
+
+Sequence< OUString > TextInputStream_getSupportedServiceNames()
+{
+ static Sequence < OUString > *pNames = 0;
+ if( ! pNames )
+ {
+ MutexGuard guard( Mutex::getGlobalMutex() );
+ if( !pNames )
+ {
+ static Sequence< OUString > seqNames(1);
+ seqNames.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME ) );
+ pNames = &seqNames;
+ }
+ }
+ return *pNames;
+}
+
+OUString OTextInputStream::getImplementationName() throw()
+{
+ return TextInputStream_getImplementationName();
+}
+
+sal_Bool OTextInputStream::supportsService(const OUString& ServiceName) throw()
+{
+ Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+
+ for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
+ if( pArray[i] == ServiceName )
+ return sal_True;
+
+ return sal_False;
+}
+
+Sequence< OUString > OTextInputStream::getSupportedServiceNames(void) throw()
+{
+ return TextInputStream_getSupportedServiceNames();
+}
+
+}
+
+using namespace io_TextInputStream;
+
+static struct ImplementationEntry g_entries[] =
+{
+ {
+ TextInputStream_CreateInstance, TextInputStream_getImplementationName ,
+ TextInputStream_getSupportedServiceNames, createSingleComponentFactory ,
+ &g_moduleCount.modCnt , 0
+ },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+extern "C"
+{
+sal_Bool SAL_CALL component_canUnload( TimeValue *pTime )
+{
+ return g_moduleCount.canUnload( &g_moduleCount , pTime );
+}
+
+//==================================================================================================
+void SAL_CALL component_getImplementationEnvironment(
+ const sal_Char ** ppEnvTypeName, uno_Environment ** )
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+//==================================================================================================
+sal_Bool SAL_CALL component_writeInfo(
+ void * pServiceManager, void * pRegistryKey )
+{
+ return component_writeInfoHelper( pServiceManager, pRegistryKey, g_entries );
+}
+//==================================================================================================
+void * SAL_CALL component_getFactory(
+ const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
+{
+ return component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
+}
+}
+
+