summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-02-21 17:43:28 -0500
committerAndras Timar <andras.timar@collabora.com>2014-02-26 00:59:49 -0600
commitd51e120019e625e98bb793f77b6f1731fa125b1d (patch)
tree88769106688dbbface54b090763c387ebe4325a2
parenta09cedbcea86e0af0db1ced6df6cf95ab5ba946b (diff)
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@googlemail.com> Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com> Reviewed-on: https://gerrit.libreoffice.org/8186 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Eike Rathke <erack@redhat.com> Reviewed-by: Andras Timar <andras.timar@collabora.com>
-rw-r--r--sc/source/filter/excel/xeformula.cxx27
-rw-r--r--sc/source/filter/excel/xetable.cxx53
-rw-r--r--sc/source/filter/inc/xeformula.hxx3
-rw-r--r--sc/source/filter/inc/xetable.hxx16
4 files changed, 87 insertions, 12 deletions
diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 19040ff0e367..654cc14f12f7 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 be28b5824a83..89a778b41229 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 615c5a35daf5..6dbee75e262c 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 a04aae116397..3299e60d99bc 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 ========================================================