sc/inc/compiler.hxx               |    3 ++
 sc/source/core/tool/compiler.cxx  |   50 ++++++++++++++++++++++++++++++++------
 sc/source/filter/excel/xename.cxx |   43 +++++++++++++++++---------------
 3 files changed, 69 insertions(+), 27 deletions(-)

New commits:
commit 0a3ee4978e90a68d1e22c36d4e41f5208b854389
Author:     Karthik Godha <[email protected]>
AuthorDate: Thu Jan 22 18:14:44 2026 +0530
Commit:     Michael Stahl <[email protected]>
CommitDate: Tue Jan 27 14:14:03 2026 +0100

    sc: XLSX - Sanitize Defined Name
    
    Sanitize defined name in XLSX export, it can't have any special
    characters ex:- ('[',']','.',' '). Also it can't contain any valid cell
    references
    
    bug-document: forum-mso-de-35646.xls
    Change-Id: Id64cd529c10801f182afa6cda165edf9e7d4ab30
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197817
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Michael Stahl <[email protected]>

diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 1af31899280e..95ac76286f0f 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -523,6 +523,9 @@ public:
                                                   const ScAddress& 
rFormulaPos);
 
     bool HasUnhandledPossibleImplicitIntersections() const { return 
!mUnhandledPossibleImplicitIntersections.empty(); }
+
+    SC_DLLPUBLIC static OUString SanitizeDefinedName(const OUString& rStr, 
const ScDocument& rDoc);
+
 #ifdef DBG_UTIL
     const std::set<OpCode>& UnhandledPossibleImplicitIntersectionsOpCodes() { 
return mUnhandledPossibleImplicitIntersectionsOpCodes; }
 #endif
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index c209b59c3549..b0a48d9ba4c4 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -5364,6 +5364,48 @@ bool ScCompiler::IsCharFlagAllConventions(
         return ScGlobal::getCharClass().isLetterNumeric( rStr, nPos );
 }
 
+OUString ScCompiler::SanitizeDefinedName(const OUString& rStr, const 
ScDocument& rDoc)
+{
+    OUStringBuffer aBuffer;
+    bool bValidName = true;
+
+    for (sal_Int32 i = 0; i < rStr.getLength(); i++)
+    {
+        sal_Unicode c = rStr[i];
+
+        // Left/Right Quotations are allowed
+        bool bQuotations = (c == 0x2018 || c == 0x2019 || c == 0x201C || c == 
0x201D);
+
+        if (ScCompiler::IsCharFlagAllConventions(rStr, i, ScCharFlags::Name) 
|| bQuotations)
+        {
+            aBuffer.append(rStr[i]);
+
+            if (!i && !ScCompiler::IsCharFlagAllConventions(rStr, i, 
ScCharFlags::CharName)
+                && !bQuotations)
+                bValidName = false;
+        }
+        else
+            aBuffer.append('_');
+    }
+
+    OUString sName = aBuffer.makeStringAndClear();
+
+    // Name can't be a valid cell reference
+    if ((ScAddress().Parse(sName, rDoc, ::formula::FormulaGrammar::CONV_XL_A1) 
!= ScRefFlags::ZERO)
+        || (ScRange().Parse(sName, rDoc, 
::formula::FormulaGrammar::CONV_XL_R1C1)
+            != ScRefFlags::ZERO))
+        bValidName = false;
+
+    if (!bValidName || sName != rStr)
+    {
+        sName = bValidName ? sName : "_" + sName;
+        SAL_WARN("sc.filter",
+                 "'" << rStr << "' is an invalid name, using '" << sName << "' 
instead.");
+    }
+
+    return sName;
+}
+
 void ScCompiler::CreateStringFromExternal( OUStringBuffer& rBuffer, const 
FormulaToken* pTokenP ) const
 {
     const FormulaToken* t = pTokenP;
@@ -5808,13 +5850,7 @@ void ScCompiler::CreateStringFromIndex( OUStringBuffer& 
rBuffer, const FormulaTo
                     aBuffer.append("[0]"
                         + 
OUStringChar(pConv->getSpecialSymbol(ScCompiler::Convention::SHEET_SEPARATOR)));
                 }
-                OUString sName = pData->GetName();
-                // If the name is a valid reference then add underscore to the 
name
-                if ((ScAddress().Parse(sName, rDoc, 
::formula::FormulaGrammar::CONV_XL_A1)
-                     != ScRefFlags::ZERO)
-                    || (ScRange().Parse(sName, rDoc, 
::formula::FormulaGrammar::CONV_XL_R1C1)
-                        != ScRefFlags::ZERO))
-                    sName = "_" + sName;
+                OUString sName = 
ScCompiler::SanitizeDefinedName(pData->GetName(), rDoc);
                 aBuffer.append(sName);
             }
         }
diff --git a/sc/source/filter/excel/xename.cxx 
b/sc/source/filter/excel/xename.cxx
index 9e9ce1bd2a00..6bd1ec43dbfe 100644
--- a/sc/source/filter/excel/xename.cxx
+++ b/sc/source/filter/excel/xename.cxx
@@ -346,33 +346,36 @@ void XclExpName::SaveXml( XclExpXmlStream& rStrm )
     // Sheets where IsExportTab is not true are not exported, so use mnXclTab
     // (1 based) to get the sheetid as of the exported document's perspective.
     SCTAB nXlsxTab = mnXclTab - 1;
-    OUString sName = maOrigName;
-    if (sName.indexOf(' ') != -1)
-    {
-        sName = sName.replace(' ', '_');
-        SAL_WARN("sc.filter",
-                 "'" << maOrigName << "' is an invalid name, using '" << sName 
<< "' instead.");
-    }
-    else
-    {
-        // If the name is a valid reference then add underscore to the name
-        if ((ScAddress().Parse(sName, GetDoc(), 
::formula::FormulaGrammar::CONV_XL_A1)
-             != ScRefFlags::ZERO)
-            || (ScRange().Parse(sName, GetDoc(), 
::formula::FormulaGrammar::CONV_XL_R1C1)
-                != ScRefFlags::ZERO))
-            sName = "_" + sName;
-    }
+    OUString sName = ScCompiler::SanitizeDefinedName(maOrigName, GetDoc());
 
     // Regenerate symbol for external references
     if (ScTokenArray* pScTokArr = GetScTokenArray())
     {
         formula::FormulaTokenArrayPlainIterator aIter(*pScTokArr);
         formula::FormulaToken* t = aIter.First();
-        while (t && !t->IsExternalRef())
-            t = aIter.Next();
+        while (t)
+        {
+            if (t->GetType() == formula::svExternal)
+            {
+                formula::FormulaToken* pNext = aIter.PeekNext();
 
-        if (t)
-            msSymbol = XclXmlUtils::ToOUString(GetCompileFormulaContext(), 
GetPos(), pScTokArr);
+                /*  Excel import generates svExternal tokens for invalid names 
and
+                for external/invalid function calls. For undefined names, new 
defined
+                name is created (XclExpFmlaCompImpl::ProcessExternal), this 
defined
+                name should follow OOXML conventions */
+                if (!pNext || (pNext->GetOpCode() != ocOpen))
+                {
+                    msSymbol = 
ScCompiler::SanitizeDefinedName(t->GetExternal(), GetDoc());
+                    break;
+                }
+            }
+            else if (t->IsExternalRef())
+            {
+                msSymbol = XclXmlUtils::ToOUString(GetCompileFormulaContext(), 
GetPos(), pScTokArr);
+                break;
+            }
+            t = aIter.Next();
+        }
     }
 
     rWorkbook->startElement( XML_definedName,

Reply via email to