[Libreoffice-commits] core.git: Branch 'libreoffice-4-2-2' - sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Tue Feb 25 23:00:13 PST 2014


 sc/source/filter/excel/xeformula.cxx |   27 +++++++++++------
 sc/source/filter/excel/xetable.cxx   |   53 ++++++++++++++++++++++++++++++++++-
 sc/source/filter/inc/xeformula.hxx   |    3 +
 sc/source/filter/inc/xetable.hxx     |   16 +++++++++-
 4 files changed, 87 insertions(+), 12 deletions(-)

New commits:
commit d51e120019e625e98bb793f77b6f1731fa125b1d
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Feb 21 17:43:28 2014 -0500

    fdo#74345: Some shared formulas cannot be exported as shared formulas.
    
    Excel's shared formula has some restrictions that Calc's doesn't have.
    So we need to check each shared formula token to see if we can export
    it as shared when saving to Excel.  Refer to the "SharedParsedFormula"
    section of the [MS-XLS] spec.
    
    Change-Id: I0ffce26700d2773bbd2893743edc6c03682c2ed7
    (cherry picked from commit 180f593fbfea238df97d006f6847bba3d9b0e317)
    Reviewed-on: https://gerrit.libreoffice.org/8165
    Tested-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    Reviewed-on: https://gerrit.libreoffice.org/8186
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>
    Reviewed-by: Andras Timar <andras.timar at collabora.com>

diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 19040ff..654cc14 100644
--- a/sc/source/filter/excel/xeformula.cxx
+++ b/sc/source/filter/excel/xeformula.cxx
@@ -323,6 +323,9 @@ public:
     /** Returns true, if the passed formula type allows 3D references only. */
     bool                Is3DRefOnly( XclFormulaType eType ) const;
 
+    bool IsRef2D( const ScSingleRefData& rRefData, bool bCheck3DFlag ) const;
+    bool IsRef2D( const ScComplexRefData& rRefData, bool bCheck3DFlag ) const;
+
     // ------------------------------------------------------------------------
 private:
     const XclExpCompConfig* GetConfigForType( XclFormulaType eType ) const;
@@ -391,8 +394,6 @@ private:
     // reference handling -----------------------------------------------------
 
     SCTAB               GetScTab( const ScSingleRefData& rRefData ) const;
-    bool                IsRef2D( const ScSingleRefData& rRefData ) const;
-    bool                IsRef2D( const ScComplexRefData& rRefData ) const;
 
     void                ConvertRefData( ScSingleRefData& rRefData, XclAddress& rXclPos,
                             bool bNatLangRef, bool bTruncMaxCol, bool bTruncMaxRow ) const;
@@ -1815,13 +1816,13 @@ SCTAB XclExpFmlaCompImpl::GetScTab( const ScSingleRefData& rRefData ) const
     return rRefData.toAbs(*mxData->mpScBasePos).Tab();
 }
 
-bool XclExpFmlaCompImpl::IsRef2D( const ScSingleRefData& rRefData ) const
+bool XclExpFmlaCompImpl::IsRef2D( const ScSingleRefData& rRefData, bool bCheck3DFlag ) const
 {
     /*  rRefData.IsFlag3D() determines if sheet name is always visible, even on
         the own sheet. If 3D references are allowed, the passed reference does
         not count as 2D reference. */
 
-    if (mxData->mpLinkMgr && rRefData.IsFlag3D())
+    if (bCheck3DFlag && rRefData.IsFlag3D())
         return false;
 
     if (rRefData.IsTabDeleted())
@@ -1833,9 +1834,9 @@ bool XclExpFmlaCompImpl::IsRef2D( const ScSingleRefData& rRefData ) const
         return rRefData.Tab() == GetCurrScTab();
 }
 
-bool XclExpFmlaCompImpl::IsRef2D( const ScComplexRefData& rRefData ) const
+bool XclExpFmlaCompImpl::IsRef2D( const ScComplexRefData& rRefData, bool bCheck3DFlag ) const
 {
-    return IsRef2D( rRefData.Ref1 ) && IsRef2D( rRefData.Ref2 );
+    return IsRef2D(rRefData.Ref1, bCheck3DFlag) && IsRef2D(rRefData.Ref2, bCheck3DFlag);
 }
 
 void XclExpFmlaCompImpl::ConvertRefData(
@@ -1938,7 +1939,7 @@ void XclExpFmlaCompImpl::ProcessCellRef( const XclExpScToken& rTokData )
             mxData->mpLinkMgr->StoreCell(aRefData, *mxData->mpScBasePos);
 
         // create the tRef, tRefErr, tRefN, tRef3d, or tRefErr3d token
-        if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
+        if (!mxData->mrCfg.mb3DRefOnly && IsRef2D(aRefData, mxData->mpLinkMgr))
         {
             // 2D reference (not in defined names, but allowed in range lists)
             sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_REFN :
@@ -1983,7 +1984,7 @@ void XclExpFmlaCompImpl::ProcessRangeRef( const XclExpScToken& rTokData )
         mxData->mpLinkMgr->StoreCellRange(aRefData, *mxData->mpScBasePos);
 
     // create the tArea, tAreaErr, tAreaN, tArea3d, or tAreaErr3d token
-    if( !mxData->mrCfg.mb3DRefOnly && IsRef2D( aRefData ) )
+    if (!mxData->mrCfg.mb3DRefOnly && IsRef2D(aRefData, mxData->mpLinkMgr))
     {
         // 2D reference (not in name formulas, but allowed in range lists)
         sal_uInt8 nBaseId = (!mxData->mpScBasePos && lclIsRefRel2D( aRefData )) ? EXC_TOKID_AREAN :
@@ -2663,6 +2664,14 @@ XclTokenArrayRef XclExpFormulaCompiler::CreateNameXFormula(
     return mxImpl->CreateNameXFormula( nExtSheet, nExtName );
 }
 
-// ============================================================================
+bool XclExpFormulaCompiler::IsRef2D( const ScSingleRefData& rRefData ) const
+{
+    return mxImpl->IsRef2D(rRefData, true);
+}
+
+bool XclExpFormulaCompiler::IsRef2D( const ScComplexRefData& rRefData ) const
+{
+    return mxImpl->IsRef2D(rRefData, true);
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx
index be28b58..89a778b 100644
--- a/sc/source/filter/excel/xetable.cxx
+++ b/sc/source/filter/excel/xetable.cxx
@@ -206,6 +206,45 @@ XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot& rRoot ) :
 {
 }
 
+bool XclExpShrfmlaBuffer::IsValidTokenArray( const ScTokenArray& rArray ) const
+{
+    using namespace formula;
+
+    FormulaToken** pTokens = rArray.GetArray();
+    sal_uInt16 nLen = rArray.GetLen();
+    for (sal_uInt16 i = 0; i < nLen; ++i)
+    {
+        const FormulaToken* p = pTokens[i];
+        switch (p->GetType())
+        {
+            case svSingleRef:
+            {
+                const ScSingleRefData& rRefData = static_cast<const ScToken*>(p)->GetSingleRef();
+                if (!GetFormulaCompiler().IsRef2D(rRefData))
+                    // Excel's shared formula cannot include 3D reference.
+                    return false;
+            }
+            break;
+            case svDoubleRef:
+            {
+                const ScComplexRefData& rRefData = static_cast<const ScToken*>(p)->GetDoubleRef();
+                if (!GetFormulaCompiler().IsRef2D(rRefData))
+                    // Excel's shared formula cannot include 3D reference.
+                    return false;
+            }
+            break;
+            case svExternalSingleRef:
+            case svExternalDoubleRef:
+            case svExternalName:
+                // External references aren't allowed.
+                return false;
+            default:
+                ;
+        }
+    }
+    return true;
+}
+
 XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
     const ScFormulaCell& rScCell, const ScAddress& rScPos )
 {
@@ -215,7 +254,19 @@ XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
         // This formula cell is not shared formula cell.
         return xRec;
 
-    XclExpShrfmlaMap::iterator aIt = maRecMap.find( pShrdScTokArr );
+    // Check to see if this shared formula contains any tokens that Excel's shared formula cannot handle.
+    if (maBadTokens.count(pShrdScTokArr) > 0)
+        // Already on the black list. Skip it.
+        return xRec;
+
+    if (!IsValidTokenArray(*pShrdScTokArr))
+    {
+        // We can't export this as shared formula.
+        maBadTokens.insert(pShrdScTokArr);
+        return xRec;
+    }
+
+    TokensType::iterator aIt = maRecMap.find(pShrdScTokArr);
     if( aIt == maRecMap.end() )
     {
         // create a new record
diff --git a/sc/source/filter/inc/xeformula.hxx b/sc/source/filter/inc/xeformula.hxx
index 615c5a3..6dbee75 100644
--- a/sc/source/filter/inc/xeformula.hxx
+++ b/sc/source/filter/inc/xeformula.hxx
@@ -79,6 +79,9 @@ public:
         @descr  This is used i.e. for linked macros in push buttons. */
     XclTokenArrayRef    CreateNameXFormula( sal_uInt16 nExtSheet, sal_uInt16 nExtName );
 
+    bool IsRef2D( const ScSingleRefData& rRefData ) const;
+    bool IsRef2D( const ScComplexRefData& rRefData ) const;
+
 private:
     typedef boost::shared_ptr< XclExpFmlaCompImpl > XclExpFmlaCompImplRef;
     XclExpFmlaCompImplRef mxImpl;
diff --git a/sc/source/filter/inc/xetable.hxx b/sc/source/filter/inc/xetable.hxx
index a04aae1..3299e60 100644
--- a/sc/source/filter/inc/xetable.hxx
+++ b/sc/source/filter/inc/xetable.hxx
@@ -31,6 +31,8 @@
 #include "xestyle.hxx"
 #include "xeextlst.hxx"
 
+#include <boost/unordered_set.hpp>
+#include <boost/unordered_map.hpp>
 #include <boost/shared_ptr.hpp>
 #include <map>
 
@@ -192,8 +194,18 @@ public:
     XclExpShrfmlaRef CreateOrExtendShrfmla( const ScFormulaCell& rScCell, const ScAddress& rScPos );
 
 private:
-    typedef ::std::map< const ScTokenArray*, XclExpShrfmlaRef > XclExpShrfmlaMap;
-    XclExpShrfmlaMap    maRecMap;       /// Map containing the SHRFMLA records.
+    /**
+     * Check for presence of token that's not allowed in Excel's shared
+     * formula. Refer to the "SharedParsedFormula" section of [MS-XLS] spec
+     * for more info.
+     */
+    bool IsValidTokenArray( const ScTokenArray& rArray ) const;
+
+    typedef boost::unordered_map<const ScTokenArray*, XclExpShrfmlaRef> TokensType;
+    typedef boost::unordered_set<const ScTokenArray*> BadTokenArraysType;
+
+    TokensType         maRecMap;    /// Map containing the SHRFMLA records.
+    BadTokenArraysType maBadTokens; /// shared tokens we should *not* export as SHRFMLA
 };
 
 // Multiple operations ========================================================


More information about the Libreoffice-commits mailing list