From 3af5437e2adf00793404957f30237ba4b9a31772 Mon Sep 17 00:00:00 2001 From: Lionel Elie Mamane Date: Fri, 8 May 2015 15:31:06 +0200 Subject: jdbc character stream: don't mix up bytes and characters Change-Id: I59352edd887982faa792b02adbb55c3f67f1d78d --- connectivity/source/drivers/jdbc/Reader.cxx | 98 ++++++++++++++++++++++++----- connectivity/source/inc/java/io/Reader.hxx | 2 + 2 files changed, 85 insertions(+), 15 deletions(-) (limited to 'connectivity') diff --git a/connectivity/source/drivers/jdbc/Reader.cxx b/connectivity/source/drivers/jdbc/Reader.cxx index 20db5108e8a5..f5f7034e17f5 100644 --- a/connectivity/source/drivers/jdbc/Reader.cxx +++ b/connectivity/source/drivers/jdbc/Reader.cxx @@ -20,6 +20,7 @@ #include "java/io/Reader.hxx" #include using namespace connectivity; +using ::com::sun::star::uno::Sequence; //************ Class: java.io.Reader @@ -52,11 +53,31 @@ sal_Int32 SAL_CALL java_io_Reader::readSomeBytes( ::com::sun::star::uno::Sequenc void SAL_CALL java_io_Reader::skipBytes( sal_Int32 nBytesToSkip ) throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception) { static jmethodID mID(NULL); - callIntMethodWithIntArg_ThrowRuntime("skip",mID,nBytesToSkip); + if(nBytesToSkip <= 0) + return; + + if(m_buf != boost::none) + { + m_buf = boost::none; + --nBytesToSkip; + } + + static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?"); + sal_Int32 nCharsToSkip = nBytesToSkip / sizeof(jchar); + callIntMethodWithIntArg_ThrowRuntime("skip",mID,nCharsToSkip); + if(nBytesToSkip % sizeof(jchar) != 0) + { + assert(nBytesToSkip % sizeof(jchar) == 1); + Sequence< sal_Int8 > aData(1); + assert(m_buf == boost::none); + readBytes(aData, 1); + } } sal_Int32 SAL_CALL java_io_Reader::available( ) throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception) { + if(m_buf != boost::none) + return 1; jboolean out; SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); @@ -69,7 +90,7 @@ sal_Int32 SAL_CALL java_io_Reader::available( ) throw(::com::sun::star::io::Not out = t.pEnv->CallBooleanMethod( object, mID); ThrowRuntimeException(t.pEnv,*this); } //t.pEnv - return out ? 1 : 0; // no way to tell *how much* is ready + return (m_buf != boost::none) + (out ? 1 : 0); // no way to tell *how much* is ready } void SAL_CALL java_io_Reader::closeInput( ) throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception) @@ -80,31 +101,78 @@ void SAL_CALL java_io_Reader::closeInput( ) throw(::com::sun::star::io::NotConn sal_Int32 SAL_CALL java_io_Reader::readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception) { - OSL_ENSURE(aData.getLength() < nBytesToRead," Sequence is smaller than BytesToRead"); - jint out(0); + OSL_ENSURE(aData.getLength() >= nBytesToRead," Sequence is smaller than BytesToRead"); + + if(nBytesToRead == 0) + return 0; + + sal_Int8 *dst(aData.getArray()); + sal_Int32 nBytesWritten(0); + + if(m_buf != boost::none) + { + if(aData.getLength() == 0) + { + aData.realloc(1); + dst = aData.getArray(); + } + *dst = *m_buf; + m_buf = boost::none; + ++nBytesWritten; + ++dst; + --nBytesToRead; + } + + if(nBytesToRead == 0) + return 0; + + sal_Int32 nCharsToRead = (nBytesToRead + 1)/2; + + jint outChars(0); SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); { - jcharArray pCharArray = t.pEnv->NewCharArray(nBytesToRead); + jcharArray pCharArray = t.pEnv->NewCharArray(nCharsToRead); static const char * cSignature = "([CII)I"; static const char * cMethodName = "read"; // Java-Call static jmethodID mID(NULL); obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID); - out = t.pEnv->CallIntMethod( object, mID, pCharArray, 0, nBytesToRead ); - if ( !out ) - ThrowRuntimeException(t.pEnv,*this); - if(out > 0) + outChars = t.pEnv->CallIntMethod( object, mID, pCharArray, 0, nCharsToRead ); + if ( !outChars ) + { + if(nBytesWritten==0) + ThrowRuntimeException(t.pEnv,*this); + else + return 1; + } + if(outChars > 0) { - jboolean p = sal_False; - if(aData.getLength() < out) - aData.realloc(out-aData.getLength()); + static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?"); + const sal_Int32 jcs = sizeof(jchar); + const sal_Int32 outBytes = std::min(nBytesToRead, outChars*jcs); + assert(outBytes == outChars*jcs || outBytes == outChars*jcs - 1); + + jboolean p = JNI_FALSE; + if(aData.getLength() < nBytesWritten + outBytes) + { + aData.realloc(nBytesWritten + outBytes); + dst = aData.getArray() + nBytesWritten; + } + jchar *outBuf(t.pEnv->GetCharArrayElements(pCharArray,&p)); - memcpy(aData.getArray(),t.pEnv->GetCharArrayElements(pCharArray,&p),out); + memcpy(dst, outBuf, outBytes); + nBytesWritten += outBytes; + if(outBytes < outChars*jcs) + { + assert(outChars*jcs - outBytes == 1); + assert(m_buf == boost::none); + m_buf = reinterpret_cast(outBuf)[outBytes]; + } } - t.pEnv->DeleteLocalRef((jcharArray)pCharArray); + t.pEnv->DeleteLocalRef(pCharArray); } //t.pEnv - return out; + return nBytesWritten; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/io/Reader.hxx b/connectivity/source/inc/java/io/Reader.hxx index dd1c5c41dcba..7dec76447f42 100644 --- a/connectivity/source/inc/java/io/Reader.hxx +++ b/connectivity/source/inc/java/io/Reader.hxx @@ -23,6 +23,7 @@ #include "java/lang/Object.hxx" #include #include +#include namespace connectivity { @@ -36,6 +37,7 @@ namespace connectivity // static Data for the Class static jclass theClass; virtual ~java_io_Reader(); + boost::optional m_buf; public: virtual jclass getMyClass() const SAL_OVERRIDE; // a Constructor, that is needed for when Returning the Object is needed: -- cgit