This is an automated email from the ASF dual-hosted git repository.

jimjag pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 17cfc6b974aad5ef7e249ab7a836e5c2f07b9187
Author: Jim Jagielski <[email protected]>
AuthorDate: Tue Nov 3 07:05:46 2026 -0500

    Read ODF 1.4 error cells in Calc and save a cell that holds only an error 
as a string
    
    Such a cell was saved as table:formula="of:#NULL!" with a float 0, which 
reloads as 0.
---
 main/sc/source/core/data/cell.cxx      |  4 ++
 main/sc/source/filter/xml/xmlcelli.cxx | 82 ++++++++++++++++++++++++++++++++--
 main/sc/source/filter/xml/xmlcelli.hxx |  1 +
 main/sc/source/filter/xml/xmlexprt.cxx |  6 ++-
 4 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/main/sc/source/core/data/cell.cxx 
b/main/sc/source/core/data/cell.cxx
index 61dd7ab0c7..9dbf2f05f9 100644
--- a/main/sc/source/core/data/cell.cxx
+++ b/main/sc/source/core/data/cell.cxx
@@ -1002,6 +1002,10 @@ void ScFormulaCell::CompileXML( ScProgress& rProgress )
                return ;
        }
 
+       // error cell read from office:value-type="error": no formula, 
recompiling would give #NAME?
+       if ( pCode->GetCodeError() && !pCode->GetLen() )
+               return;
+
        ScCompiler aComp( pDocument, aPos, *pCode);
     aComp.SetGrammar(eTempGrammar);
     String aFormula, aFormulaNmsp;
diff --git a/main/sc/source/filter/xml/xmlcelli.cxx 
b/main/sc/source/filter/xml/xmlcelli.cxx
index dcc8c1da4c..d7b0af5435 100644
--- a/main/sc/source/filter/xml/xmlcelli.cxx
+++ b/main/sc/source/filter/xml/xmlcelli.cxx
@@ -121,7 +121,8 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( 
ScXMLImport& rImport,
        bHasTextImport(sal_False),
        bIsFirstTextImport(sal_False),
        bSolarMutexLocked(sal_False),
-       bFormulaTextResult(sal_False)
+       bFormulaTextResult(sal_False),
+       bIsError(sal_False)
 {
        rXMLImport.SetRemoveLastChar(sal_False);
        rXMLImport.GetTables().AddColumn(bTempIsCovered);
@@ -167,6 +168,7 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( 
ScXMLImport& rImport,
             break;
             case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
                 nCellType = GetScImport().GetCellType(sValue);
+                bIsError = sValue.equalsAscii("error");
                 bIsEmpty = sal_False;
             break;
             case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
@@ -309,6 +311,33 @@ void ScXMLTableRowCellContext::SetCursorOnTextImport(const 
rtl::OUString& rOUTem
     }
 }
 
+// Collects the plain text of a text:p in an error cell, including text nested 
in text:span and the like.
+class ScXMLErrorTextContext : public SvXMLImportContext
+{
+    ScXMLTableRowCellContext* pCellContext;
+    ScXMLErrorTextContext* pParent;
+    rtl::OUStringBuffer aText;
+public:
+    ScXMLErrorTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const 
rtl::OUString& rLName,
+                           ScXMLTableRowCellContext* pCell, 
ScXMLErrorTextContext* pTop ) :
+        SvXMLImportContext( rImport, nPrfx, rLName ), pCellContext( pCell ), 
pParent( pTop ) {}
+
+    virtual SvXMLImportContext* CreateChildContext( sal_uInt16 nPrfx, const 
rtl::OUString& rLName,
+        const uno::Reference< xml::sax::XAttributeList >& )
+    {
+        return new ScXMLErrorTextContext( GetImport(), nPrfx, rLName, NULL, 
pParent ? pParent : this );
+    }
+    virtual void Characters( const rtl::OUString& rChars )
+    {
+        (pParent ? pParent->aText : aText).append( rChars );
+    }
+    virtual void EndElement()
+    {
+        if (pCellContext)
+            pCellContext->SetString( aText.makeStringAndClear() );
+    }
+};
+
 SvXMLImportContext *ScXMLTableRowCellContext::CreateChildContext( sal_uInt16 
nPrefix,
                                                                                
        const ::rtl::OUString& rLName,
                                                                                
        const ::com::sun::star::uno::Reference<
@@ -325,7 +354,9 @@ SvXMLImportContext 
*ScXMLTableRowCellContext::CreateChildContext( sal_uInt16 nPr
                        bIsEmpty = sal_False;
                        bTextP = sal_True;
             com::sun::star::table::CellAddress aCellPos = 
rXMLImport.GetTables().GetRealCellPos();
-                       if (((nCellType == util::NumberFormat::TEXT) || 
bFormulaTextResult) &&
+                       if (bIsError && !pOUFormula)
+                               pContext = new 
ScXMLErrorTextContext(rXMLImport, nPrefix, rLName, this, NULL);
+                       else if (((nCellType == util::NumberFormat::TEXT) || 
bFormulaTextResult) &&
                 !rXMLImport.GetTables().IsPartOfMatrix(aCellPos.Column, 
aCellPos.Row))
                        {
                                if (!bHasTextImport)
@@ -756,6 +787,34 @@ bool lcl_IsEmptyOrNote( ScDocument* pDoc, const 
table::CellAddress& rCurrentPos
     return ( !pCell || pCell->GetCellType() == CELLTYPE_NOTE );
 }
 
+static sal_uInt16 lcl_GetErrorCode( const rtl::OUString& rText )
+{
+    static const struct { const sal_Char* pName; sal_uInt16 nCode; } aErrors[] 
=
+    {
+        { "#NULL!", errNoCode }, { "#DIV/0!", errDivisionByZero }, { 
"#VALUE!", errNoValue },
+        { "#REF!", errNoRef }, { "#NAME?", errNoName }, { "#NUM!", 
errIllegalFPOperation },
+        { "#N/A", NOTAVAILABLE }
+    };
+    for (size_t i = 0; i < sizeof(aErrors)/sizeof(aErrors[0]); ++i)
+    {
+        if (rText.equalsAscii(aErrors[i].pName) || String(rText) == 
ScGlobal::GetErrorString(aErrors[i].nCode))
+            return aErrors[i].nCode;
+    }
+    if (rText.matchAsciiL("Err:", 4) && rText.getLength() > 4)
+    {
+        sal_Int32 nCode = 0;
+        for (sal_Int32 i = 4; i < rText.getLength() && nCode <= NOTAVAILABLE; 
++i)
+        {
+            if (rText[i] < '0' || rText[i] > '9')
+                return errNoValue;
+            nCode = nCode * 10 + (rText[i] - '0');
+        }
+        if (nCode > 0 && nCode <= NOTAVAILABLE)
+            return static_cast<sal_uInt16>(nCode);
+    }
+    return errNoValue;
+}
+
 void ScXMLTableRowCellContext::EndElement()
 {
        if (!bHasSubTable)
@@ -993,7 +1052,24 @@ void ScXMLTableRowCellContext::EndElement()
                                                                            
break;
                                                                    default:
                                                                            {
-                                                                               
    DBG_ERROR("no cell type given");
+                                                                               
    if (bIsError)
+                                                                               
    {
+                                                                               
            if (!rTables.IsPartOfMatrix(aCurrentPos.Column, aCurrentPos.Row))
+                                                                               
            {
+                                                                               
                    LockSolarMutex();
+                                                                               
                    ScAddress aScAddress;
+                                                                               
                    ScUnoConversion::FillScAddress( aScAddress, aCurrentPos );
+                                                                               
                    ScDocument* pDoc = rXMLImport.GetDocument();
+                                                                               
                    ScFormulaCell* pErrCell = new ScFormulaCell( pDoc, 
aScAddress );
+                                                                               
                    pErrCell->SetErrCode( lcl_GetErrorCode(
+                                                                               
                            (pOUTextValue && pOUTextValue->getLength()) ? 
*pOUTextValue :
+                                                                               
                            pOUTextContent ? *pOUTextContent : rtl::OUString() 
) );
+                                                                               
                    pDoc->PutCell( aScAddress, pErrCell );
+                                                                               
            }
+                                                                               
            rXMLImport.ProgressBarIncrement(sal_False);
+                                                                               
    }
+                                                                               
    else
+                                                                               
            DBG_ERROR("no cell type given");
                                                                            }
                                                                            
break;
                                                                    }
diff --git a/main/sc/source/filter/xml/xmlcelli.hxx 
b/main/sc/source/filter/xml/xmlcelli.hxx
index 0736a852f1..fccb9bc553 100644
--- a/main/sc/source/filter/xml/xmlcelli.hxx
+++ b/main/sc/source/filter/xml/xmlcelli.hxx
@@ -72,6 +72,7 @@ class ScXMLTableRowCellContext : public SvXMLImportContext
        sal_Bool        bIsFirstTextImport;
        sal_Bool        bSolarMutexLocked;
        sal_Bool        bFormulaTextResult;
+       sal_Bool        bIsError;
 
        const ScXMLImport& GetScImport() const { return (const 
ScXMLImport&)GetImport(); }
        ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
diff --git a/main/sc/source/filter/xml/xmlexprt.cxx 
b/main/sc/source/filter/xml/xmlexprt.cxx
index 06223b227c..1a5693d171 100644
--- a/main/sc/source/filter/xml/xmlexprt.cxx
+++ b/main/sc/source/filter/xml/xmlexprt.cxx
@@ -2981,7 +2981,9 @@ void ScXMLExport::WriteCell(ScMyCell& aCell, sal_Int32 
nEqualCellCount)
                        {
                                rtl::OUStringBuffer sFormula;
                                ScFormulaCell* pFormulaCell((ScFormulaCell*) 
pBaseCell);
-                               if (!bIsMatrix || (bIsMatrix && 
bIsFirstMatrixCell))
+                               // an error without a formula (error cell, 
Excel import) has no valid formula to write
+                               const bool bIsErrorOnly = 
pFormulaCell->GetCode()->GetCodeError() && !pFormulaCell->GetCode()->GetLen();
+                               if (!bIsErrorOnly && (!bIsMatrix || (bIsMatrix 
&& bIsFirstMatrixCell)))
                                {
                     const formula::FormulaGrammar::Grammar eGrammar = 
pDoc->GetStorageGrammar();
                     sal_uInt16 nNamespacePrefix = (eGrammar == 
formula::FormulaGrammar::GRAM_ODFF ? XML_NAMESPACE_OF : XML_NAMESPACE_OOOC);
@@ -2996,7 +2998,7 @@ void ScXMLExport::WriteCell(ScMyCell& aCell, sal_Int32 
nEqualCellCount)
                                                AddAttribute(sAttrFormula, 
GetNamespaceMap().GetQNameByKey( nNamespacePrefix, sOUFormula.copy(1, 
sOUFormula.getLength() - 2), sal_False ));
                                        }
                                }
-                               if (pFormulaCell->IsValue())
+                               if (!bIsErrorOnly && pFormulaCell->IsValue())
                                {
                                        sal_Bool bIsStandard;
                                        rtl::OUString sCurrency;

Reply via email to