sc/qa/unit/data/xlsx/tdf166413.xlsx |binary sc/qa/unit/subsequent_export_test4.cxx | 35 +++++++++++++++++++++++++++++++++ sc/source/filter/excel/xecontent.cxx | 12 ++++++----- 3 files changed, 42 insertions(+), 5 deletions(-)
New commits: commit f5a8496680df5e8bc0b4152de42a16a0c7ef71ac Author: Aron Budea <aron.bu...@collabora.com> AuthorDate: Thu May 1 13:48:42 2025 +0930 Commit: Aron Budea <aron.bu...@collabora.com> CommitDate: Fri May 2 04:32:21 2025 +0200 tdf166413 sc: escape quotes in XLSX cond. formatting fixed formula ...during export, otherwise Excel fails to open file Change-Id: I50bc16ff4064a84ae3601cfa539d7b90f5441607 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184852 Tested-by: Jenkins Reviewed-by: Aron Budea <aron.bu...@collabora.com> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> (cherry picked from commit 55169df2f6e4f8deb9c042b81cc3ff4f01cbf522) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184858 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/sc/qa/unit/data/xlsx/tdf166413.xlsx b/sc/qa/unit/data/xlsx/tdf166413.xlsx new file mode 100644 index 000000000000..ae6e58a8fa09 Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf166413.xlsx differ diff --git a/sc/qa/unit/subsequent_export_test4.cxx b/sc/qa/unit/subsequent_export_test4.cxx index af4c770962df..72e07d6f01be 100644 --- a/sc/qa/unit/subsequent_export_test4.cxx +++ b/sc/qa/unit/subsequent_export_test4.cxx @@ -2208,6 +2208,41 @@ CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf165886) assertXPathContent(pSheet, "/x:worksheet/x:sheetData/x:row[4]/x:c[2]/x:f", u"OR(D4=0,D4<>’’)"); } +CPPUNIT_TEST_FIXTURE(ScExportTest4, testTdf166413) +{ + createScDoc("xlsx/tdf166413.xlsx"); + + save(u"Calc Office Open XML"_ustr); + + xmlDocUniquePtr pSheet = parseExport(u"xl/worksheets/sheet1.xml"_ustr); + CPPUNIT_ASSERT(pSheet); + + // Without the accompanying fix in place, this test would have failed with + // - Expected: NOT(ISERROR(SEARCH("""ABC""",A1))) + // - Actual : NOT(ISERROR(SEARCH(""ABC"",A1))) + assertXPathContent(pSheet, + "/x:worksheet/x:conditionalFormatting[@sqref=\"A1:C1\"]/x:cfRule/x:formula", + u"NOT(ISERROR(SEARCH(\"\"\"ABC\"\"\",A1)))"); + // Similarly + // - Expected: ISERROR(SEARCH("""ABC""",A2)) + // - Actual : ISERROR(SEARCH(""ABC"",A2)) + assertXPathContent(pSheet, + "/x:worksheet/x:conditionalFormatting[@sqref=\"A2:C2\"]/x:cfRule/x:formula", + u"ISERROR(SEARCH(\"\"\"ABC\"\"\",A2))"); + // Similarly + // - Expected: LEFT(A3,LEN("""ABC"""))="""ABC""" + // - Actual : LEFT(A3,LEN(""ABC""))=""ABC"" + assertXPathContent(pSheet, + "/x:worksheet/x:conditionalFormatting[@sqref=\"A3:C3\"]/x:cfRule/x:formula", + u"LEFT(A3,LEN(\"\"\"ABC\"\"\"))=\"\"\"ABC\"\"\""); + // Similarly + // - Expected: RIGHT(A4,LEN("""ABC"""))="""ABC""" + // - Actual : RIGHT(A4,LEN(""ABC""))=""ABC"" + assertXPathContent(pSheet, + "/x:worksheet/x:conditionalFormatting[@sqref=\"A4:C4\"]/x:cfRule/x:formula", + u"RIGHT(A4,LEN(\"\"\"ABC\"\"\"))=\"\"\"ABC\"\"\""); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/excel/xecontent.cxx b/sc/source/filter/excel/xecontent.cxx index 263c55ee5f5d..4c903738a441 100644 --- a/sc/source/filter/excel/xecontent.cxx +++ b/sc/source/filter/excel/xecontent.cxx @@ -1001,11 +1001,13 @@ bool RequiresFixedFormula(ScConditionMode eMode) return false; } -OString GetFixedFormula(ScConditionMode eMode, const ScAddress& rAddress, std::string_view rText) +OString GetFixedFormula(ScConditionMode eMode, const ScAddress& rAddress, const OString& rText) { OStringBuffer aBuffer; XclXmlUtils::ToOString(aBuffer, rAddress); OString aPos = aBuffer.makeStringAndClear(); + // double quotes in rText need to be escaped + const OString aText = rText.replaceAll("\""_ostr, "\"\""_ostr); switch (eMode) { case ScConditionMode::Error: @@ -1013,13 +1015,13 @@ OString GetFixedFormula(ScConditionMode eMode, const ScAddress& rAddress, std::s case ScConditionMode::NoError: return OString("NOT(ISERROR(" + aPos + "))") ; case ScConditionMode::BeginsWith: - return OString("LEFT(" + aPos + ",LEN(\"" + rText + "\"))=\"" + rText + "\""); + return OString("LEFT(" + aPos + ",LEN(\"" + aText + "\"))=\"" + aText + "\""); case ScConditionMode::EndsWith: - return OString("RIGHT(" + aPos +",LEN(\"" + rText + "\"))=\"" + rText + "\""); + return OString("RIGHT(" + aPos +",LEN(\"" + aText + "\"))=\"" + aText + "\""); case ScConditionMode::ContainsText: - return OString(OString::Concat("NOT(ISERROR(SEARCH(\"") + rText + "\"," + aPos + ")))"); + return OString(OString::Concat("NOT(ISERROR(SEARCH(\"") + aText + "\"," + aPos + ")))"); case ScConditionMode::NotContainsText: - return OString(OString::Concat("ISERROR(SEARCH(\"") + rText + "\"," + aPos + "))"); + return OString(OString::Concat("ISERROR(SEARCH(\"") + aText + "\"," + aPos + "))"); default: break; }