summaryrefslogtreecommitdiff
path: root/sc/source/filter/excel
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel')
-rw-r--r--sc/source/filter/excel/excform8.cxx81
-rw-r--r--sc/source/filter/excel/read.cxx4
-rw-r--r--sc/source/filter/excel/xilink.cxx230
3 files changed, 288 insertions, 27 deletions
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx
index aebb75418f36..3cfc20d5aeba 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>
@@ -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..75b0e1b01468 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);