diff options
Diffstat (limited to 'sc/source/filter')
-rw-r--r-- | sc/source/filter/excel/excform.cxx | 19 | ||||
-rw-r--r-- | sc/source/filter/excel/excform8.cxx | 83 | ||||
-rw-r--r-- | sc/source/filter/excel/read.cxx | 4 | ||||
-rw-r--r-- | sc/source/filter/excel/xilink.cxx | 234 | ||||
-rw-r--r-- | sc/source/filter/excel/xistyle.cxx | 4 | ||||
-rw-r--r-- | sc/source/filter/inc/excform.hxx | 11 | ||||
-rw-r--r-- | sc/source/filter/inc/xilink.hxx | 23 |
7 files changed, 326 insertions, 52 deletions
diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx index 62f3622cd87a..949cb0fb0615 100644 --- a/sc/source/filter/excel/excform.cxx +++ b/sc/source/filter/excel/excform.cxx @@ -480,7 +480,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s else aIn >> nXclFunc; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, pFuncInfo->mnMaxParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -498,7 +498,7 @@ ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, s else aIn >> nXclFunc; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, nParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, nParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -1525,7 +1525,7 @@ sal_Bool ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sa return !rRangeList.empty(); } -void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz, sal_uInt8 nMinParamCount ) +void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz ) { TokenId eParam[ 256 ]; sal_Int32 nLauf; @@ -1589,19 +1589,6 @@ void ExcelToSc::DoMulArgs( DefTokenId eId, sal_uInt8 nAnz, sal_uInt8 nMinParamCo } } - // FIXME: ideally we'd want to import all missing args, but this - // conflicts with lots of fn's understanding of nParams - we need - // a function table, and pre-call argument normalisation 1st. - sal_Int16 nLastRemovable = nLast - nMinParamCount; - - // skip missing parameters at end of parameter list - while( nSkipEnd < nLastRemovable && - aPool.IsSingleOp( eParam[ nSkipEnd + 1 ], ocMissing ) ) - nSkipEnd++; - -// fprintf (stderr, "Fn %d nSkipEnd %d nLast %d nMinParamCnt %d %d\n", -// eId, nSkipEnd, nLast, nMinParamCount, nLastRemovable); - // [Parameter{;Parameter}] if( nLast > nSkipEnd ) { diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx index aebb75418f36..f989abc3c196 100644 --- a/sc/source/filter/excel/excform8.cxx +++ b/sc/source/filter/excel/excform8.cxx @@ -42,9 +42,51 @@ #include "externalrefmgr.hxx" #include <vector> +#include <cstring> +using ::rtl::OUString; +using ::rtl::OUStringBuffer; using ::std::vector; +namespace { + +/** + * Extract a file path from OLE link path. An OLE link path is expected to + * be in the following format: + * + * Excel.Sheet.8 \3 [file path] + */ +bool extractFilePath(const OUString& rUrl, OUString& rPath) +{ + const char* prefix = "Excel.Sheet.8\3"; + size_t nPrefixLen = ::std::strlen(prefix); + + sal_Int32 n = rUrl.getLength(); + if (n <= static_cast<sal_Int32>(nPrefixLen)) + // needs to have the specified prefix. + return false; + + OUStringBuffer aBuf; + const sal_Unicode* p = rUrl.getStr(); + for (size_t i = 0; i < static_cast<size_t>(n); ++i, ++p) + { + if (i < nPrefixLen) + { + sal_Unicode pc = static_cast<sal_Unicode>(*prefix++); + if (pc != *p) + return false; + + continue; + } + aBuf.append(*p); + } + + rPath = aBuf.makeStringAndClear(); + return true; +} + +} + ExcelToSc8::ExternalTabInfo::ExternalTabInfo() : mnFileId(0), mbExternal(false) { @@ -92,6 +134,20 @@ bool ExcelToSc8::Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId); } +bool ExcelToSc8::HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo) +{ + const String* pUrl = rLinkMan.GetSupbookUrl(nXtiIndex); + if (!pUrl) + return false; + + OUString aPath; + if (!extractFilePath(*pUrl, aPath)) + // file path extraction failed. + return false; + + OUString aFileUrl = ScGlobal::GetAbsDocName(aPath, GetDocShell()); + return rExtName.CreateOleData(GetDoc(), aFileUrl, rExtInfo.mnFileId, rExtInfo.maTabName, rExtInfo.maRange); +} // if bAllowArrays is false stream seeks to first byte after <nFormulaLen> // otherwise it will seek to the first byte past additional content after <nFormulaLen> @@ -419,7 +475,7 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, aIn >> nParamCount >> nXclFunc; nParamCount &= 0x7F; if( const XclFunctionInfo* pFuncInfo = maFuncProv.GetFuncInfoFromXclFunc( nXclFunc ) ) - DoMulArgs( pFuncInfo->meOpCode, nParamCount, pFuncInfo->mnMinParamCount ); + DoMulArgs( pFuncInfo->meOpCode, nParamCount ); else DoMulArgs( ocNoName, 0 ); } @@ -682,8 +738,29 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, aStack << aPool.Store( ocEuroConvert, String() ); } break; - - default: // OLE link + case xlExtOLE: + { + ExternalTabInfo aExtInfo; + if (HandleOleLink(nXtiIndex, *pExtName, aExtInfo)) + { + if (aExtInfo.maRange.aStart == aExtInfo.maRange.aEnd) + { + // single cell + aSRD.InitAddress(aExtInfo.maRange.aStart); + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD); + } + else + { + // range + aCRD.InitRange(aExtInfo.maRange); + aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD); + } + } + else + aStack << aPool.Store(ocNoName, pExtName->GetName()); + } + break; + default: { aPool << ocBad; aPool >> aStack; diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx index 70feaa4e4e22..96e68a9df01f 100644 --- a/sc/source/filter/excel/read.cxx +++ b/sc/source/filter/excel/read.cxx @@ -1125,8 +1125,8 @@ FltError ImportExcel8::Read( void ) case 0x9D: AutoFilterInfo(); break;// AUTOFILTERINFO case 0x9E: AutoFilter(); break; // AUTOFILTER case 0x0208: Row34(); break; // ROW [ 34 ] - case 0x0021: - case 0x0221: Array34(); break; // ARRAY [ 34 ] + case EXC_ID2_ARRAY: + case EXC_ID3_ARRAY: Array34(); break; // ARRAY [ 34 ] case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[ 345 ] case 0x04BC: Shrfmla(); break; // SHRFMLA [ 5 ] case 0x0867: SheetProtection(); break; // SHEETPROTECTION diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx index 634a723238a6..492fe5d2033c 100644 --- a/sc/source/filter/excel/xilink.cxx +++ b/sc/source/filter/excel/xilink.cxx @@ -44,6 +44,9 @@ #include <boost/ptr_container/ptr_vector.hpp> using ::std::vector; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + // ============================================================================ // *** Helper classes *** @@ -284,7 +287,61 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa // External names ============================================================= -XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) +XclImpExtName::MOper::MOper(XclImpStream& rStrm) : + mxCached(new ScMatrix(0,0)) +{ + SCSIZE nLastCol = rStrm.ReaduInt8(); + SCSIZE nLastRow = rStrm.ReaduInt16(); + mxCached->Resize(nLastCol+1, nLastRow+1); + for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow) + { + for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol) + { + sal_uInt8 nOp; + rStrm >> nOp; + switch (nOp) + { + case 0x01: + { + double fVal = rStrm.ReadDouble(); + mxCached->PutDouble(fVal, nCol, nRow); + } + break; + case 0x02: + { + OUString aStr = rStrm.ReadUniString(); + mxCached->PutString(aStr, nCol, nRow); + } + break; + case 0x04: + { + bool bVal = rStrm.ReaduInt8(); + mxCached->PutBoolean(bVal, nCol, nRow); + rStrm.Ignore(7); + } + break; + case 0x10: + { + sal_uInt8 nErr = rStrm.ReaduInt8(); + // TODO: Map the error code from xls to calc. + mxCached->PutError(nErr, nCol, nRow); + rStrm.Ignore(7); + } + break; + default: + rStrm.Ignore(8); + } + } + } +} + +const ScMatrix& XclImpExtName::MOper::GetCache() const +{ + return *mxCached; +} + +XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) : + mpMOper(NULL) { sal_uInt16 nFlags; sal_uInt8 nLen; @@ -312,36 +369,45 @@ XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE ); } - if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) ) - mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) ); - - if (meType == xlExtName) + switch (meType) { - // TODO: For now, only global external names are supported. In future - // we should extend this to supporting per-sheet external names. - if (mnStorageId == 0) - { - if (pFormulaConv) + case xlExtDDE: + if (rStrm.GetRecLeft() > 1) + mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm)); + break; + case xlExtName: + // TODO: For now, only global external names are supported. In future + // we should extend this to supporting per-sheet external names. + if (mnStorageId == 0) { - const ScTokenArray* pArray = NULL; - sal_uInt16 nFmlaLen; - rStrm >> nFmlaLen; - vector<String> aTabNames; - sal_uInt16 nCount = rSupbook.GetTabCount(); - aTabNames.reserve(nCount); - for (sal_uInt16 i = 0; i < nCount; ++i) - aTabNames.push_back(rSupbook.GetTabName(i)); - - pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames); - if (pArray) - mxArray.reset(pArray->Clone()); + if (pFormulaConv) + { + const ScTokenArray* pArray = NULL; + sal_uInt16 nFmlaLen; + rStrm >> nFmlaLen; + vector<String> aTabNames; + sal_uInt16 nCount = rSupbook.GetTabCount(); + aTabNames.reserve(nCount); + for (sal_uInt16 i = 0; i < nCount; ++i) + aTabNames.push_back(rSupbook.GetTabName(i)); + + pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames); + if (pArray) + mxArray.reset(pArray->Clone()); + } } - } + break; + case xlExtOLE: + mpMOper = new MOper(rStrm); + break; + default: + ; } } XclImpExtName::~XclImpExtName() { + delete mpMOper; } void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const @@ -361,6 +427,124 @@ void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) co pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray); } +namespace { + +/** + * Decompose the name into sheet name and range name. An OLE link name is + * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1 + * notation. + */ +bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange) +{ + sal_Int32 n = rName.getLength(); + const sal_Unicode* p = rName.getStr(); + OUStringBuffer aBuf; + bool bInSheet = true; + for (sal_Int32 i = 0; i < n; ++i, ++p) + { + if (i == 0) + { + // first character must be '!'. + if (*p != '!') + return false; + continue; + } + + if (*p == '!') + { + // sheet name to range separator. + if (!bInSheet) + return false; + rSheet = aBuf.makeStringAndClear(); + bInSheet = false; + continue; + } + + aBuf.append(*p); + } + + rRange = aBuf.makeStringAndClear(); + return true; +} + +} + +bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl, + sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const +{ + if (!mpMOper) + return false; + + OUString aSheet, aRangeStr; + if (!extractSheetAndRange(maName, aSheet, aRangeStr)) + return false; + + ScRange aRange; + sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1); + if ((nRes & SCA_VALID) != SCA_VALID) + return false; + + if (aRange.aStart.Tab() != aRange.aEnd.Tab()) + // We don't support multi-sheet range for this. + return false; + + const ScMatrix& rCache = mpMOper->GetCache(); + SCSIZE nC, nR; + rCache.GetDimensions(nC, nR); + if (!nC || !nR) + // cache matrix is empty. + return false; + + ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager(); + sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl); + ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL); + if (!xTab) + // cache table creation failed. + return false; + + xTab->setWholeTableCached(); + for (SCSIZE i = 0; i < nR; ++i) + { + for (SCSIZE j = 0; j < nC; ++j) + { + SCCOL nCol = aRange.aStart.Col() + j; + SCROW nRow = aRange.aStart.Row() + i; + + ScMatrixValue aVal = rCache.Get(j, i); + switch (aVal.nType) + { + case SC_MATVAL_BOOLEAN: + { + bool b = aVal.GetBoolean(); + ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + case SC_MATVAL_VALUE: + { + ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + case SC_MATVAL_STRING: + { + const String& rStr = aVal.GetString(); + ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr)); + xTab->setCell(nCol, nRow, pToken, 0, false); + } + break; + default: + ; + } + } + } + + rFileId = nFileId; + rTabName = aSheet; + rRange = aRange; + return true; +} + bool XclImpExtName::HasFormulaTokens() const { return (mxArray.get() != NULL); @@ -516,9 +700,9 @@ void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const { DBG_ASSERT( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" ); - if (meType == EXC_SBTYPE_SELF || nXclIndex >= maExtNameList.size()) + if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size()) return NULL; - return &maExtNameList.at( nXclIndex - 1 ); + return &maExtNameList[nXclIndex-1]; } bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index d4eb332b2fb0..11381e54bb4e 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -1321,8 +1321,8 @@ void XclImpXF::ApplyPatternToAttrList( pPat = static_cast<const ScPatternAttr*>(&aCache.ApplyTo(*pPat, true)); } - - if (pPat) + // Make sure we skip unnamed styles. + if (pPat && pPat->GetStyleName()) { // Check for a gap between the last entry and this one. bool bHasGap = false; diff --git a/sc/source/filter/inc/excform.hxx b/sc/source/filter/inc/excform.hxx index 0744bdf52c64..ebc3696e9a0f 100644 --- a/sc/source/filter/inc/excform.hxx +++ b/sc/source/filter/inc/excform.hxx @@ -52,7 +52,7 @@ protected: const XclBiff meBiff; // --------------------------------------------------------------- - void DoMulArgs( DefTokenId eId, sal_uInt8 nNumArgs, sal_uInt8 mnMinParamCount = 0 ); + void DoMulArgs( DefTokenId eId, sal_uInt8 nNumArgs ); void ExcRelToScRel( sal_uInt16 nRow, sal_uInt8 nCol, ScSingleRefData&, const sal_Bool bName ); @@ -104,6 +104,7 @@ inline sal_Bool ExcelToSc::IsComplRowRange( const sal_uInt16 nRow1, const sal_uI // ============================================================================ class XclImpLinkManager; +class XclImpExtName; class ExcelToSc8 : public ExcelToSc { @@ -111,9 +112,10 @@ public: struct ExternalTabInfo { - String maTabName; - sal_uInt16 mnFileId; - bool mbExternal; + ScRange maRange; + ::rtl::OUString maTabName; + sal_uInt16 mnFileId; + bool mbExternal; ExternalTabInfo(); }; @@ -128,6 +130,7 @@ private: virtual bool Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo ); + bool HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo); public: ExcelToSc8( const XclImpRoot& rRoot ); virtual ~ExcelToSc8(); diff --git a/sc/source/filter/inc/xilink.hxx b/sc/source/filter/inc/xilink.hxx index 2f06ddb2f7b0..2b2e9ac8a03c 100644 --- a/sc/source/filter/inc/xilink.hxx +++ b/sc/source/filter/inc/xilink.hxx @@ -32,6 +32,7 @@ #include <map> #include "xllink.hxx" #include "xiroot.hxx" +#include "scmatrix.hxx" /* ============================================================================ Classes for import of different kinds of internal/external references. @@ -113,6 +114,19 @@ class XclImpSupbook; @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */ class XclImpExtName { + /** + * MOper, multiple operands, stores cached values of external range + * specified in the record. + */ + class MOper + { + public: + MOper(XclImpStream& rStrm); + const ScMatrix& GetCache() const; + private: + ScMatrixRef mxCached; + }; + public: /** Reads the external name from the stream. */ explicit XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, @@ -125,6 +139,14 @@ public: void CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const; + /** + * Create OLE link data. OLE link data is converted to external + * reference, since OLE link doesn't work cross-platform, and is not very + * reliable even on Windows. + */ + bool CreateOleData(ScDocument& rDoc, const ::rtl::OUString& rUrl, + sal_uInt16& rFileId, ::rtl::OUString& rTabName, ScRange& rRange) const; + bool HasFormulaTokens() const; inline XclImpExtNameType GetType() const { return meType; } @@ -136,6 +158,7 @@ private: typedef ::std::auto_ptr< ScTokenArray > TokenArrayPtr; XclImpCachedMatrixPtr mxDdeMatrix; /// Cached results of the DDE link. + MOper* mpMOper; /// Cached values for OLE link TokenArrayPtr mxArray; /// Formula tokens for external name. String maName; /// The name of the external name. sal_uInt32 mnStorageId; /// Storage ID for OLE object storages. |