diff options
author | Kohei Yoshida <kohei.yoshida@suse.com> | 2012-01-10 14:26:14 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@suse.com> | 2012-01-10 14:29:23 -0500 |
commit | d041d1469227f5536abba938a21ab7c8e9d35719 (patch) | |
tree | ed31127cb81aabe1d8c79c9c6beaabb4a4df9273 | |
parent | e9419b946857e396cab8ff88c3da5708e2edcf4f (diff) |
fdo#42624: Defer formula token conversion for defined names (xls import).
This is necessary for handling names that cross-reference each other.
-rw-r--r-- | sc/source/filter/excel/excform8.cxx | 8 | ||||
-rw-r--r-- | sc/source/filter/excel/read.cxx | 1 | ||||
-rw-r--r-- | sc/source/filter/excel/xiname.cxx | 125 | ||||
-rw-r--r-- | sc/source/filter/inc/xiname.hxx | 36 | ||||
-rw-r--r-- | sc/source/filter/inc/xistream.hxx | 2 |
5 files changed, 119 insertions, 53 deletions
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx index f06f9c88c93f..9693fe8e58c3 100644 --- a/sc/source/filter/excel/excform8.cxx +++ b/sc/source/filter/excel/excform8.cxx @@ -487,11 +487,11 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, const XclImpName* pName = GetNameManager().GetName( nUINT16 ); if (pName) { - if (pName->GetScRangeData()) - aStack << aPool.StoreName(nUINT16, pName->IsGlobal()); - else - // used-defined macro name. + if (pName->IsMacro()) + // user-defined macro name. aStack << aPool.Store(ocMacro, pName->GetXclName()); + else + aStack << aPool.StoreName(nUINT16, pName->IsGlobal()); } } break; diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx index 81e6f6a039d5..30acae7d36e1 100644 --- a/sc/source/filter/excel/read.cxx +++ b/sc/source/filter/excel/read.cxx @@ -1001,6 +1001,7 @@ FltError ImportExcel8::Read( void ) rNumFmtBfr.CreateScFormats(); rXFBfr.CreateUserStyles(); rPTableMgr.ReadPivotCaches( maStrm ); + rNameMgr.ConvertAllTokens(); eAkt = EXC_STATE_BEFORE_SHEET; } break; diff --git a/sc/source/filter/excel/xiname.cxx b/sc/source/filter/excel/xiname.cxx index f2f5e8d4f20a..9cdfe775f94e 100644 --- a/sc/source/filter/excel/xiname.cxx +++ b/sc/source/filter/excel/xiname.cxx @@ -40,19 +40,26 @@ // *** Implementation *** // ============================================================================ +XclImpName::TokenStrmData::TokenStrmData( XclImpStream& rStrm ) : + mrStrm(rStrm), mnStrmPos(0), mnStrmSize(0) {} + XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : XclImpRoot( rStrm.GetRoot() ), mpScData( 0 ), mcBuiltIn( EXC_BUILTIN_UNKNOWN ), mnScTab( SCTAB_MAX ), - mbFunction( false ), - mbVBName( false ) + meNameType( RT_NAME ), + mnXclTab( EXC_NAME_GLOBAL ), + mnNameIndex( nXclNameIdx ), + mbVBName( false ), + mbMacro( false ), + mpTokensData( NULL ) { ExcelToSc& rFmlaConv = GetOldFmlaConverter(); // 1) *** read data from stream *** --------------------------------------- - sal_uInt16 nFlags = 0, nFmlaSize = 0, nExtSheet = EXC_NAME_GLOBAL, nXclTab = EXC_NAME_GLOBAL; + sal_uInt16 nFlags = 0, nFmlaSize = 0, nExtSheet = EXC_NAME_GLOBAL; sal_uInt8 nNameLen = 0, nShortCut; switch( GetBiff() ) @@ -78,7 +85,7 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : case EXC_BIFF5: case EXC_BIFF8: { - rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize >> nExtSheet >> nXclTab; + rStrm >> nFlags >> nShortCut >> nNameLen >> nFmlaSize >> nExtSheet >> mnXclTab; rStrm.Ignore( 4 ); } break; @@ -94,8 +101,9 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : // 2) *** convert sheet index and name *** -------------------------------- // functions and VBA - mbFunction = ::get_flag( nFlags, EXC_NAME_FUNC ); + bool bFunction = ::get_flag( nFlags, EXC_NAME_FUNC ); mbVBName = ::get_flag( nFlags, EXC_NAME_VB ); + mbMacro = ::get_flag( nFlags, EXC_NAME_PROC ); // get built-in name, or convert characters invalid in Calc bool bBuiltIn = ::get_flag( nFlags, EXC_NAME_BUILTIN ); @@ -131,11 +139,9 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : rtl::OUString aRealOrigName = maScName; // add index for local names - if( nXclTab != EXC_NAME_GLOBAL ) + if( mnXclTab != EXC_NAME_GLOBAL ) { - sal_uInt16 nUsedTab = (GetBiff() == EXC_BIFF8) ? nXclTab : nExtSheet; - // do not rename sheet-local names by default, this breaks VBA scripts -// maScName.Append( '_' ).Append( String::CreateFromInt32( nUsedTab ) ); + sal_uInt16 nUsedTab = (GetBiff() == EXC_BIFF8) ? mnXclTab : nExtSheet; // TODO: may not work for BIFF5, handle skipped sheets (all BIFF) mnScTab = static_cast< SCTAB >( nUsedTab - 1 ); } @@ -144,7 +150,6 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : rFmlaConv.Reset(); const ScTokenArray* pTokArr = 0; // pointer to token array, owned by rFmlaConv - RangeType nNameType = RT_NAME; if( ::get_flag( nFlags, EXC_NAME_BIG ) ) { @@ -153,7 +158,7 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : } else if( bBuiltIn ) { - SCsTAB const nLocalTab = (nXclTab == EXC_NAME_GLOBAL) ? SCTAB_MAX : (nXclTab - 1); + SCsTAB const nLocalTab = (mnXclTab == EXC_NAME_GLOBAL) ? SCTAB_MAX : (mnXclTab - 1); // --- print ranges or title ranges --- rStrm.PushPosition(); @@ -161,11 +166,11 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : { case EXC_BUILTIN_PRINTAREA: if( rFmlaConv.Convert( GetPrintAreaBuffer(), rStrm, nFmlaSize, nLocalTab, FT_RangeName ) == ConvOK ) - nNameType |= RT_PRINTAREA; + meNameType |= RT_PRINTAREA; break; case EXC_BUILTIN_PRINTTITLES: if( rFmlaConv.Convert( GetTitleAreaBuffer(), rStrm, nFmlaSize, nLocalTab, FT_RangeName ) == ConvOK ) - nNameType |= RT_COLHEADER | RT_ROWHEADER; + meNameType |= RT_COLHEADER | RT_ROWHEADER; break; } rStrm.PopPosition(); @@ -188,7 +193,7 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : break; case EXC_BUILTIN_CRITERIA: GetFilterManager().AddAdvancedRange( aRange ); - nNameType |= RT_CRITERIA; + meNameType |= RT_CRITERIA; break; case EXC_BUILTIN_EXTRACT: if( pTokArr->IsValidReference( aRange ) ) @@ -200,46 +205,75 @@ XclImpName::XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ) : } else if( nFmlaSize > 0 ) { - // regular defined name - rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, true, FT_RangeName ); + // Regular defined name. We need to convert the tokens after all the + // names have been registered (for cross-referenced names). + mpTokensData.reset(new TokenStrmData(rStrm)); + mpTokensData->mnStrmPos = rStrm.GetSvStreamPos(); + rStrm.StorePosition(mpTokensData->maStrmPos); + mpTokensData->mnStrmSize = nFmlaSize; } - // 4) *** create a defined name in the Calc document *** ------------------ + if (pTokArr && !bFunction && !mbVBName) + InsertName(pTokArr); +} + +bool XclImpName::IsMacro() const +{ + return mbMacro; +} + +void XclImpName::ConvertTokens() +{ + if (!mpTokensData) + return; + + ExcelToSc& rFmlaConv = GetOldFmlaConverter(); + rFmlaConv.Reset(); + const ScTokenArray* pArray = NULL; + + XclImpStreamPos aOldPos; + XclImpStream& rStrm = mpTokensData->mrStrm; + rStrm.StorePosition(aOldPos); + rStrm.RestorePosition(mpTokensData->maStrmPos); + rFmlaConv.Convert(pArray, rStrm, mpTokensData->mnStrmSize, true, FT_RangeName); + rStrm.RestorePosition(aOldPos); - // do not ignore hidden names (may be regular names created by VBA scripts) - if( pTokArr /*&& (bBuiltIn || !::get_flag( nFlags, EXC_NAME_HIDDEN ))*/ && !mbFunction && !mbVBName ) + if (pArray) + InsertName(pArray); +} + +void XclImpName::InsertName(const ScTokenArray* pArray) +{ + // create the Calc name data + ScRangeData* pData = new ScRangeData(GetDocPtr(), maScName, *pArray, ScAddress(), meNameType); + pData->GuessPosition(); // calculate base position for relative refs + pData->SetIndex( mnNameIndex ); // used as unique identifier in formulas + if (mnXclTab == EXC_NAME_GLOBAL) { - // create the Calc name data - ScRangeData* pData = new ScRangeData( GetDocPtr(), maScName, *pTokArr, ScAddress(), nNameType ); - pData->GuessPosition(); // calculate base position for relative refs - pData->SetIndex( nXclNameIdx ); // used as unique identifier in formulas - if (nXclTab == EXC_NAME_GLOBAL) + if (!GetDoc().GetRangeName()->insert(pData)) + pData = NULL; + } + else + { + ScRangeName* pLocalNames = GetDoc().GetRangeName(mnScTab); + if (pLocalNames) { - if (!GetDoc().GetRangeName()->insert(pData)) + if (!pLocalNames->insert(pData)) pData = NULL; } - else - { - ScRangeName* pLocalNames = GetDoc().GetRangeName(mnScTab); - if (pLocalNames) - { - if (!pLocalNames->insert(pData)) - pData = NULL; - } - if (GetBiff() == EXC_BIFF8 && pData) + if (GetBiff() == EXC_BIFF8 && pData) + { + ScRange aRange; + // discard deleted ranges ( for the moment at least ) + if ( pData->IsValidReference( aRange ) ) { - ScRange aRange; - // discard deleted ranges ( for the moment at least ) - if ( pData->IsValidReference( aRange ) ) - { - GetExtDocOptions().GetOrCreateTabSettings( nXclTab ); - } + GetExtDocOptions().GetOrCreateTabSettings( mnXclTab ); } } - if (pData) - mpScData = pData; // cache for later use } + if (pData) + mpScData = pData; // cache for later use } // ---------------------------------------------------------------------------- @@ -279,6 +313,13 @@ const XclImpName* XclImpNameManager::GetName( sal_uInt16 nXclNameIdx ) const return ( nXclNameIdx > maNameList.size() ) ? NULL : &(maNameList.at( nXclNameIdx - 1 )); } +void XclImpNameManager::ConvertAllTokens() +{ + XclImpNameList::iterator it = maNameList.begin(), itEnd = maNameList.end(); + for (; it != itEnd; ++it) + it->ConvertTokens(); +} + // ============================================================================ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/inc/xiname.hxx b/sc/source/filter/inc/xiname.hxx index 8d05d680d690..f4e55c37645b 100644 --- a/sc/source/filter/inc/xiname.hxx +++ b/sc/source/filter/inc/xiname.hxx @@ -32,17 +32,31 @@ #include <boost/ptr_container/ptr_vector.hpp> #include "xlname.hxx" #include "xiroot.hxx" +#include "xistream.hxx" -//class ScDocument; -//class ScTokenArray; +#include "rangenam.hxx" + +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> // ============================================================================ class ScRangeData; +class ScTokenArray; /** Represents a defined name. It may be related to a single sheet or global. */ -class XclImpName : protected XclImpRoot +class XclImpName : protected XclImpRoot, public boost::noncopyable { + struct TokenStrmData + { + XclImpStream& mrStrm; + XclImpStreamPos maStrmPos; + sal_Size mnStrmPos; + sal_Size mnStrmSize; + + TokenStrmData( XclImpStream& rStrm ); + }; + public: explicit XclImpName( XclImpStream& rStrm, sal_uInt16 nXclNameIdx ); @@ -51,17 +65,25 @@ public: inline SCTAB GetScTab() const { return mnScTab; } inline const ScRangeData* GetScRangeData() const { return mpScData; } inline bool IsGlobal() const { return mnScTab == SCTAB_MAX; } - inline bool IsFunction() const { return mbFunction; } inline bool IsVBName() const { return mbVBName; } + bool IsMacro() const; + void ConvertTokens(); private: + void InsertName(const ScTokenArray* pArray); + String maXclName; /// Original name read from the file. String maScName; /// Name inserted into the Calc document. const ScRangeData* mpScData; /// Pointer to Calc defined name (no ownership). sal_Unicode mcBuiltIn; /// Excel built-in name index. SCTAB mnScTab; /// Calc sheet index of local names. - bool mbFunction; /// true = Name refers to a function (add-in or VBA). - bool mbVBName; /// true = Visual Basic procedure or function. + RangeType meNameType; + sal_uInt16 mnXclTab; + sal_uInt16 mnNameIndex; + bool mbVBName:1; /// true = Visual Basic procedure or function. + bool mbMacro:1; /// Whether it's a user-defined macro. + + boost::scoped_ptr<TokenStrmData> mpTokensData; /// For later conversion of token array. }; // ---------------------------------------------------------------------------- @@ -90,6 +112,8 @@ public: @return Pointer to the defined name or 0 on error. */ const XclImpName* GetName( sal_uInt16 nXclNameIdx ) const; + void ConvertAllTokens(); + private: typedef boost::ptr_vector< XclImpName > XclImpNameList; XclImpNameList maNameList; diff --git a/sc/source/filter/inc/xistream.hxx b/sc/source/filter/inc/xistream.hxx index 89dab91a7392..a80e478a1d20 100644 --- a/sc/source/filter/inc/xistream.hxx +++ b/sc/source/filter/inc/xistream.hxx @@ -436,12 +436,12 @@ public: /** Returns the stream size. */ inline sal_Size GetSvStreamSize() const { return mnStreamSize; } -private: /** Stores current stream position into rPos. */ void StorePosition( XclImpStreamPos& rPos ); /** Restores stream position contained in rPos. */ void RestorePosition( const XclImpStreamPos& rPos ); +private: /** Seeks to next raw record header and reads record ID and size. @descr This is a "raw" function, means that stream members are inconsistent after return. Does only change mnRawRecId, mnRawRecSize, |