filter/source/msfilter/rtfutil.cxx          |    3 ++-
 svtools/source/svrtf/rtfout.cxx             |    3 ++-
 sw/qa/extras/rtfexport/rtfexport8.cxx       |   21 +++++++++++++++++++++
 sw/source/filter/ww8/rtfattributeoutput.cxx |    3 ++-
 4 files changed, 27 insertions(+), 3 deletions(-)

New commits:
commit 77db5679983cc58603c2001a9b8dfcea7faa8574
Author:     Mike Kaganski <[email protected]>
AuthorDate: Thu Jul 24 11:10:28 2025 +0500
Commit:     Xisco Fauli <[email protected]>
CommitDate: Mon Aug 11 12:11:54 2025 +0200

    tdf#167660: export \uN as signed 16-bit values
    
    This is as specified in Rich Text Format (RTF) Specification, Version 1.9.1,
    "Unicode RTF"; and this matches what Word outputs.
    
    Change-Id: Ia1b7c2dc40d5908a78a30ea249c1ec0a13945b87
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188257
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>
    Signed-off-by: Xisco Fauli <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189302

diff --git a/filter/source/msfilter/rtfutil.cxx 
b/filter/source/msfilter/rtfutil.cxx
index bb1b85876bfd..093be55f6ff6 100644
--- a/filter/source/msfilter/rtfutil.cxx
+++ b/filter/source/msfilter/rtfutil.cxx
@@ -186,7 +186,8 @@ OString OutChar(sal_Unicode c, int* pUCMode, 
rtl_TextEncoding eDestEnc, bool* pS
                         aBuf.append(' ');
                         *pUCMode = nLen;
                     }
-                    aBuf.append("\u" + 
OString::number(static_cast<sal_Int32>(c)));
+                    // Rich Text Format (RTF) Specification, Version 1.9.1, 
"Unicode RTF"
+                    aBuf.append("\u" + 
OString::number(static_cast<sal_Int16>(c))); // signed!
                 }
 
                 for (sal_Int32 nI = 0; nI < nLen; ++nI)
diff --git a/svtools/source/svrtf/rtfout.cxx b/svtools/source/svrtf/rtfout.cxx
index 843256dc2d47..da2bd7b103f8 100644
--- a/svtools/source/svrtf/rtfout.cxx
+++ b/svtools/source/svrtf/rtfout.cxx
@@ -154,8 +154,9 @@ SvStream& Out_Char(SvStream& rStream, sal_Unicode c,
                                .WriteNumberAsString( nLen ).WriteOString( " " 
);
                             *pUCMode = nLen;
                         }
+                        // Rich Text Format (RTF) Specification, Version 
1.9.1, "Unicode RTF"
                         rStream.WriteOString( "\u" )
-                           .WriteNumberAsString(c);
+                           .WriteNumberAsString(static_cast<sal_Int16>(c)); // 
signed!
                     }
 
                     for (sal_Int32 nI = 0; nI < nLen; ++nI)
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index ff05ce5c4fcd..9c36b8596691 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -992,6 +992,27 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167569)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf167660)
+{
+    // Create a document, add there a character in a range U+8000-U+FFFF, 
export to RTF
+    createSwDoc();
+    CPPUNIT_ASSERT(getSwDocShell());
+    CPPUNIT_ASSERT(getSwDocShell()->GetWrtShell());
+    getSwDocShell()->GetWrtShell()->Insert(u"\uFB02"_ustr);
+
+    save(mpFilter);
+
+    // Test that the character is exported as a negative integer
+
+    SvFileStream stream(maTempFile.GetFileName(), StreamMode::READ);
+    auto size = stream.remainingSize();
+    std::vector<char> buffer(size);
+    CPPUNIT_ASSERT_EQUAL(size_t(size), stream.ReadBytes(buffer.data(), 
buffer.size()));
+    std::string_view buffer_view(buffer.data(), buffer.size());
+    CPPUNIT_ASSERT_EQUAL(std::string_view::npos, buffer_view.find("\u64258"));
+    CPPUNIT_ASSERT(buffer_view.find("\u-1278") != std::string_view::npos);
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 4579ba5e3f75..e2b66f87c278 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -1867,7 +1867,8 @@ void RtfAttributeOutput::NumberingLevel(sal_uInt8 nLevel, 
sal_uInt16 nStart,
         m_rExport.Strm().WriteOString("\'01");
         sal_Unicode cChar = rNumberingString[0];
         m_rExport.Strm().WriteOString("\u");
-        m_rExport.Strm().WriteNumberAsString(cChar);
+        // Rich Text Format (RTF) Specification, Version 1.9.1, "Unicode RTF"
+        m_rExport.Strm().WriteNumberAsString(static_cast<sal_Int16>(cChar)); 
// signed!
         m_rExport.Strm().WriteOString(" ?");
     }
     else

Reply via email to