io/source/TextInputStream/TextInputStream.cxx   |   53 ++++++++++-----------
 io/source/TextOutputStream/TextOutputStream.cxx |   58 ++++++++++--------------
 2 files changed, 50 insertions(+), 61 deletions(-)

New commits:
commit 8985041da5359892e627922fc64cfe70dcc2ca57
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Aug 22 13:30:36 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Aug 22 18:40:40 2025 +0200

    Throw from OText{Input,Output}Stream::setEncoding on unknown encoding
    
    Before this, it was possible to pass an arbitrary string to the method,
    and have no way of knowing about the problem. IllegalArgumentException
    is derived from RuntimeException, which is explicitly documented to be
    allowed at every interface method, signalling errors not covered by the
    interface method specification, so this is not an API change.
    
    Change-Id: I038f7765ec3f332f0e787351fa032feeef2cefb0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190048
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/io/source/TextInputStream/TextInputStream.cxx 
b/io/source/TextInputStream/TextInputStream.cxx
index 9edf80dcc0e7..c00c04c7cc74 100644
--- a/io/source/TextInputStream/TextInputStream.cxx
+++ b/io/source/TextInputStream/TextInputStream.cxx
@@ -30,6 +30,7 @@
 #include <com/sun/star/io/IOException.hpp>
 #include <com/sun/star/io/NotConnectedException.hpp>
 #include <com/sun/star/io/XTextInputStream2.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 
 #include <optional>
@@ -165,8 +166,6 @@ OUString OTextInputStream::implReadString( const Sequence< 
sal_Unicode >& Delimi
     {
         setEncoding( u"utf8"_ustr );
     }
-    if (!moEncoding)
-        return aRetStr;
 
     // Only for bFindLineEnd
     constexpr sal_Unicode cLineEndChar1 = ' ';
@@ -310,7 +309,7 @@ void OTextInputStream::setEncoding( const OUString& 
Encoding )
     OString aOEncodingStr = OUStringToOString( Encoding, 
RTL_TEXTENCODING_ASCII_US );
     rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( 
aOEncodingStr.getStr() );
     if( RTL_TEXTENCODING_DONTKNOW == encoding )
-        return;
+        throw IllegalArgumentException("Unknown encoding '" + Encoding + "'", 
getXWeak(), 0);
 
     moEncoding.emplace(encoding);
 }
diff --git a/io/source/TextOutputStream/TextOutputStream.cxx 
b/io/source/TextOutputStream/TextOutputStream.cxx
index 6790c3ae231c..893db57fe52a 100644
--- a/io/source/TextOutputStream/TextOutputStream.cxx
+++ b/io/source/TextOutputStream/TextOutputStream.cxx
@@ -27,6 +27,7 @@
 
 #include <com/sun/star/io/IOException.hpp>
 #include <com/sun/star/io/XTextOutputStream2.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 
 #include <optional>
@@ -147,8 +148,6 @@ void OTextOutputStream::writeString( const OUString& 
aString )
     {
         setEncoding( u"utf8"_ustr );
     }
-    if (!moEncoding)
-        return;
 
     Sequence<sal_Int8> aByteSeq = implConvert( aString );
     mxStream->writeBytes( aByteSeq );
@@ -159,7 +158,7 @@ void OTextOutputStream::setEncoding( const OUString& 
Encoding )
     OString aOEncodingStr = OUStringToOString( Encoding, 
RTL_TEXTENCODING_ASCII_US );
     rtl_TextEncoding encoding = rtl_getTextEncodingFromMimeCharset( 
aOEncodingStr.getStr() );
     if( RTL_TEXTENCODING_DONTKNOW == encoding )
-        return;
+        throw IllegalArgumentException("Unknown encoding '" + Encoding + "'", 
getXWeak(), 0);
 
     moEncoding.emplace(encoding);
 }
commit ec4628b7976a2840eebe38da3fe2bddb1d6b1573
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Aug 22 13:07:26 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Aug 22 18:40:35 2025 +0200

    Avoid memory leak in OText{Input,Output}Stream::setEncoding
    
    These classes used to only destroy their converter and context in
    dtor; but their setEncoding API method can be called several times,
    and every time after the initial initialization, it leaked active
    converter and context.
    
    Change-Id: Ie71cf73e4bc36a94b433898bc6bb3041dab700e7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190047
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/io/source/TextInputStream/TextInputStream.cxx 
b/io/source/TextInputStream/TextInputStream.cxx
index 287783ca3fad..9edf80dcc0e7 100644
--- a/io/source/TextInputStream/TextInputStream.cxx
+++ b/io/source/TextInputStream/TextInputStream.cxx
@@ -32,6 +32,7 @@
 #include <com/sun/star/io/XTextInputStream2.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 
+#include <optional>
 #include <vector>
 
 namespace com::sun::star::uno { class XComponentContext; }
@@ -53,10 +54,22 @@ class OTextInputStream : public WeakImplHelper< 
XTextInputStream2, XServiceInfo
 {
     Reference< XInputStream > mxStream;
 
-    // Encoding
-    bool mbEncodingInitialized;
-    rtl_TextToUnicodeConverter  mConvText2Unicode;
-    rtl_TextToUnicodeContext    mContextText2Unicode;
+    struct Encoding_t
+    {
+        rtl_TextToUnicodeConverter  mConvText2Unicode;
+        rtl_TextToUnicodeContext    mContextText2Unicode;
+        Encoding_t(rtl_TextEncoding encoding)
+        {
+            mConvText2Unicode = rtl_createTextToUnicodeConverter(encoding);
+            mContextText2Unicode = 
rtl_createTextToUnicodeContext(mConvText2Unicode);
+        }
+        ~Encoding_t()
+        {
+            rtl_destroyTextToUnicodeContext(mConvText2Unicode, 
mContextText2Unicode);
+            rtl_destroyTextToUnicodeConverter(mConvText2Unicode);
+        }
+    };
+    std::optional<Encoding_t> moEncoding;
     Sequence<sal_Int8>          mSeqSource;
 
     // Internal buffer for characters that are already converted successfully
@@ -76,7 +89,6 @@ class OTextInputStream : public WeakImplHelper< 
XTextInputStream2, XServiceInfo
 
 public:
     OTextInputStream();
-    virtual ~OTextInputStream() override;
 
     // Methods XTextInputStream
     virtual OUString SAL_CALL readLine(  ) override;
@@ -104,25 +116,13 @@ public:
 }
 
 OTextInputStream::OTextInputStream()
-    : mbEncodingInitialized(false)
-    , mConvText2Unicode(nullptr)
-    , mContextText2Unicode(nullptr)
-    , mSeqSource(READ_BYTE_COUNT)
+    : mSeqSource(READ_BYTE_COUNT)
     , mvBuffer(INITIAL_UNICODE_BUFFER_CAPACITY, 0)
     , mnCharsInBuffer(0)
     , mbReachedEOF(false)
 {
 }
 
-OTextInputStream::~OTextInputStream()
-{
-    if( mbEncodingInitialized )
-    {
-        rtl_destroyTextToUnicodeContext( mConvText2Unicode, 
mContextText2Unicode );
-        rtl_destroyTextToUnicodeConverter( mConvText2Unicode );
-    }
-}
-
 // Check uninitialized object
 
 void OTextInputStream::checkNull()
@@ -161,11 +161,11 @@ OUString OTextInputStream::implReadString( const 
Sequence< sal_Unicode >& Delimi
                                            bool bRemoveDelimiter, bool 
bFindLineEnd )
 {
     OUString aRetStr;
-    if( !mbEncodingInitialized )
+    if (!moEncoding)
     {
         setEncoding( u"utf8"_ustr );
     }
-    if( !mbEncodingInitialized )
+    if (!moEncoding)
         return aRetStr;
 
     // Only for bFindLineEnd
@@ -265,8 +265,8 @@ sal_Int32 OTextInputStream::implReadNext()
             // All invalid characters are transformed to the unicode undefined 
char
             sal_Size nSrcCvtBytes = 0;
             mnCharsInBuffer += rtl_convertTextToUnicode(
-                                mConvText2Unicode,
-                                mContextText2Unicode,
+                                moEncoding->mConvText2Unicode,
+                                moEncoding->mContextText2Unicode,
                                 reinterpret_cast<const 
char*>(mSeqSource.getConstArray() + nSourceCount),
                                 mSeqSource.getLength() - nSourceCount,
                                 mvBuffer.data() + mnCharsInBuffer,
@@ -312,9 +312,7 @@ void OTextInputStream::setEncoding( const OUString& 
Encoding )
     if( RTL_TEXTENCODING_DONTKNOW == encoding )
         return;
 
-    mbEncodingInitialized = true;
-    mConvText2Unicode = rtl_createTextToUnicodeConverter( encoding );
-    mContextText2Unicode = rtl_createTextToUnicodeContext( mConvText2Unicode );
+    moEncoding.emplace(encoding);
 }
 
 
@@ -382,7 +380,7 @@ extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
 io_OTextInputStream_get_implementation(
     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
 {
-    return cppu::acquire(new OTextInputStream());
+    return cppu::acquire(new OTextInputStream);
 }
 
 
diff --git a/io/source/TextOutputStream/TextOutputStream.cxx 
b/io/source/TextOutputStream/TextOutputStream.cxx
index f576b9881672..6790c3ae231c 100644
--- a/io/source/TextOutputStream/TextOutputStream.cxx
+++ b/io/source/TextOutputStream/TextOutputStream.cxx
@@ -29,6 +29,8 @@
 #include <com/sun/star/io/XTextOutputStream2.hpp>
 #include <com/sun/star/lang/XServiceInfo.hpp>
 
+#include <optional>
+
 namespace com::sun::star::uno { class XComponentContext; }
 
 using namespace ::cppu;
@@ -44,19 +46,28 @@ class OTextOutputStream : public WeakImplHelper< 
XTextOutputStream2, XServiceInf
 {
     Reference< XOutputStream > mxStream;
 
-    // Encoding
-    bool mbEncodingInitialized;
-    rtl_UnicodeToTextConverter  mConvUnicode2Text;
-    rtl_UnicodeToTextContext    mContextUnicode2Text;
+    struct Encoding_t
+    {
+        rtl_UnicodeToTextConverter  mConvUnicode2Text;
+        rtl_UnicodeToTextContext    mContextUnicode2Text;
+        Encoding_t(rtl_TextEncoding encoding)
+        {
+            mConvUnicode2Text = rtl_createUnicodeToTextConverter(encoding);
+            mContextUnicode2Text = 
rtl_createUnicodeToTextContext(mConvUnicode2Text);
+        }
+        ~Encoding_t()
+        {
+            rtl_destroyUnicodeToTextContext(mConvUnicode2Text, 
mContextUnicode2Text);
+            rtl_destroyUnicodeToTextConverter(mConvUnicode2Text);
+        }
+    };
+    std::optional<Encoding_t> moEncoding;
 
     Sequence<sal_Int8> implConvert( const OUString& rSource );
     /// @throws IOException
     void checkOutputStream() const;
 
 public:
-    OTextOutputStream();
-    virtual ~OTextOutputStream() override;
-
     // Methods XTextOutputStream
     virtual void SAL_CALL writeString( const OUString& aString ) override;
     virtual void SAL_CALL setEncoding( const OUString& Encoding ) override;
@@ -78,22 +89,6 @@ public:
 
 }
 
-OTextOutputStream::OTextOutputStream()
-    : mbEncodingInitialized(false)
-    , mConvUnicode2Text(nullptr)
-    , mContextUnicode2Text(nullptr)
-{
-}
-
-OTextOutputStream::~OTextOutputStream()
-{
-    if( mbEncodingInitialized )
-    {
-        rtl_destroyUnicodeToTextContext( mConvUnicode2Text, 
mContextUnicode2Text );
-        rtl_destroyUnicodeToTextConverter( mConvUnicode2Text );
-    }
-}
-
 Sequence<sal_Int8> OTextOutputStream::implConvert( const OUString& rSource )
 {
     const sal_Unicode *puSource = rSource.getStr();
@@ -115,8 +110,8 @@ Sequence<sal_Int8> OTextOutputStream::implConvert( const 
OUString& rSource )
     while( true )
     {
         nTargetCount += rtl_convertUnicodeToText(
-                                    mConvUnicode2Text,
-                                    mContextUnicode2Text,
+                                    moEncoding->mConvUnicode2Text,
+                                    moEncoding->mContextUnicode2Text,
                                     &( puSource[nSourceCount] ),
                                     nSourceSize - nSourceCount ,
                                     &( pTarget[nTargetCount] ),
@@ -148,11 +143,11 @@ Sequence<sal_Int8> OTextOutputStream::implConvert( const 
OUString& rSource )
 void OTextOutputStream::writeString( const OUString& aString )
 {
     checkOutputStream();
-    if( !mbEncodingInitialized )
+    if (!moEncoding)
     {
         setEncoding( u"utf8"_ustr );
     }
-    if( !mbEncodingInitialized )
+    if (!moEncoding)
         return;
 
     Sequence<sal_Int8> aByteSeq = implConvert( aString );
@@ -166,9 +161,7 @@ void OTextOutputStream::setEncoding( const OUString& 
Encoding )
     if( RTL_TEXTENCODING_DONTKNOW == encoding )
         return;
 
-    mbEncodingInitialized = true;
-    mConvUnicode2Text   = rtl_createUnicodeToTextConverter( encoding );
-    mContextUnicode2Text = rtl_createUnicodeToTextContext( mConvUnicode2Text );
+    moEncoding.emplace(encoding);
 }
 
 
@@ -232,7 +225,7 @@ extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
 io_OTextOutputStream_get_implementation(
     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
 {
-    return cppu::acquire(new OTextOutputStream());
+    return cppu::acquire(new OTextOutputStream);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to