vcl/qa/cppunit/pdfexport/pdfexport.cxx  |    4 ++--
 vcl/qa/cppunit/pdfexport/pdfexport2.cxx |   16 ++++++++--------
 vcl/source/filter/ipdf/pdfdocument.cxx  |   23 ++++++++++++++++++++++-
 3 files changed, 32 insertions(+), 11 deletions(-)

New commits:
commit d9090f2e222a32dec306f9ef6ae2328c265cb56c
Author:     Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 16:51:18 2026 +0200
Commit:     Miklos Vajna <[email protected]>
CommitDate: Fri Feb 27 09:10:39 2026 +0100

    Parse hexadecimal escapes in vcl::filter::PDFNameElement
    
    We write these escapes rather liberally in COSWriter::appendName(), so we
    should parse them when reading.
    
    (cherry picked from commit 247430c3edd811744f525d09da00035702cbbf6a)
    
    Change-Id: Ie9f7626de287fd5038ca198a7143a95c3471ce92
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200561
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 98c2f9616c26..1e22b31ae4f3 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2275,7 +2275,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157816)
     auto pTypeD2 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD2->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeD2->GetValue());
     auto pSD2 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD2->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pSD2->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pSD2->GetValue());
 
     auto pKidsD2 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD2->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKidsD2);
@@ -3326,7 +3326,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf142806)
     auto pTypeD1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeD1->GetValue());
     auto pSD1 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pSD1->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pSD1->GetValue());
 
     auto pKidsD1 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD1->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKidsD1);
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx 
b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
index b9c560f422b5..e0bc9337994e 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx
@@ -1950,7 +1950,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157817)
     auto pTypeT00 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT00->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeT00->GetValue());
     auto pST00 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT00->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Contents#20Heading"_ostr, pST00->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Contents Heading"_ostr, pST00->GetValue());
 
     auto pRefKidT1 = 
dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsTv[1]);
     CPPUNIT_ASSERT(pRefKidT1);
@@ -1972,7 +1972,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157817)
     auto pTypeT10 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT10->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeT10->GetValue());
     auto pST10 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT10->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Contents#201"_ostr, pST10->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Contents 1"_ostr, pST10->GetValue());
 
     auto pKidsT10 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT10->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKidsT10);
@@ -2009,7 +2009,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157817)
     auto pTypeT20 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT20->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeT20->GetValue());
     auto pST20 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT20->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Contents#201"_ostr, pST20->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Contents 1"_ostr, pST20->GetValue());
 
     auto pKidsT20 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT20->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKidsT20);
@@ -2046,7 +2046,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157817)
     auto pTypeT30 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT30->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pTypeT30->GetValue());
     auto pST30 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT30->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Contents#201"_ostr, pST30->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Contents 1"_ostr, pST30->GetValue());
 
     auto pKidsT30 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT30->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKidsT30);
@@ -2972,7 +2972,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157397)
     auto pType12 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject12->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType12->GetValue());
     auto pS12 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject12->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pS12->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pS12->GetValue());
 
     auto pKids12 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject12->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKids12);
@@ -3046,7 +3046,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157397)
     auto pType13 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject13->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType13->GetValue());
     auto pS13 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject13->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pS13->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pS13->GetValue());
 
     auto pKids13 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject13->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKids13);
@@ -3119,7 +3119,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157397)
     auto pType14 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject14->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType14->GetValue());
     auto pS14 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject14->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pS14->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pS14->GetValue());
 
     auto pKids14 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject14->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKids14);
@@ -3193,7 +3193,7 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf157397)
     auto pType16 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject16->Lookup("Type"_ostr));
     CPPUNIT_ASSERT_EQUAL("StructElem"_ostr, pType16->GetValue());
     auto pS16 = 
dynamic_cast<vcl::filter::PDFNameElement*>(pObject16->Lookup("S"_ostr));
-    CPPUNIT_ASSERT_EQUAL("Text#20body"_ostr, pS16->GetValue());
+    CPPUNIT_ASSERT_EQUAL("Text body"_ostr, pS16->GetValue());
 
     auto pKids16 = 
dynamic_cast<vcl::filter::PDFArrayElement*>(pObject16->Lookup("K"_ostr));
     CPPUNIT_ASSERT(pKids16);
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx 
b/vcl/source/filter/ipdf/pdfdocument.cxx
index bce5265de69e..814877919510 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -2884,7 +2884,28 @@ bool PDFNameElement::Read(SvStream& rStream)
             SAL_INFO("vcl.filter", "PDFNameElement::Read: m_aValue is '" << 
m_aValue << "'");
             return true;
         }
-        aBuf.append(ch);
+        // Parse hexadecimal escapes
+        if (ch == '#')
+        {
+            unsigned char hex1, hex2;
+            rStream.ReadUChar(hex1);
+            rStream.ReadUChar(hex2);
+            if (!rStream.eof() && rtl::isAsciiHexDigit(hex1) && 
rtl::isAsciiHexDigit(hex2))
+            {
+                unsigned char hexBuf[2] = { hex1, hex2 };
+                aBuf.append(static_cast<char>(
+                    OString(reinterpret_cast<const char*>(hexBuf), 
2).toInt32(16)));
+            }
+            else
+            {
+                SAL_WARN("vcl.filter", "PDFNameElement::Read: invalid hex 
escape");
+                return false;
+            }
+        }
+        else
+        {
+            aBuf.append(ch);
+        }
         rStream.ReadChar(ch);
     }
 

Reply via email to