Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "xilink.hxx"
21 : #include "document.hxx"
22 : #include "formulacell.hxx"
23 : #include "scextopt.hxx"
24 : #include "tablink.hxx"
25 : #include "xistream.hxx"
26 : #include "xihelper.hxx"
27 : #include "xiname.hxx"
28 : #include "excform.hxx"
29 : #include "tokenarray.hxx"
30 : #include "externalrefmgr.hxx"
31 : #include "scmatrix.hxx"
32 : #include <svl/sharedstringpool.hxx>
33 :
34 : #include <vector>
35 : #include <boost/ptr_container/ptr_vector.hpp>
36 :
37 : using ::std::vector;
38 :
39 : // *** Helper classes ***
40 :
41 : // Cached external cells ======================================================
42 :
43 : /**
44 : * Contains the address and value of an external referenced cell.
45 : * Note that this is non-copyable, so cannot be used in most stl/boost containers.
46 : */
47 4 : class XclImpCrn : public XclImpCachedValue
48 : {
49 : public:
50 : /** Reads a cached value and stores it with its cell address. */
51 : explicit XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
52 :
53 2 : const XclAddress& GetAddress() const { return maXclPos;}
54 :
55 : private:
56 : XclAddress maXclPos; /// Excel position of the cached cell.
57 : };
58 :
59 : // Sheet in an external document ==============================================
60 :
61 : /** Contains the name and sheet index of one sheet in an external document. */
62 : class XclImpSupbookTab
63 : {
64 : public:
65 : /** Stores the sheet name and marks the sheet index as invalid.
66 : The sheet index is set while creating the Calc sheet with CreateTable(). */
67 : explicit XclImpSupbookTab( const OUString& rTabName );
68 : ~XclImpSupbookTab();
69 :
70 4 : inline const OUString& GetTabName() const { return maTabName; }
71 :
72 : /** Reads a CRN record (external referenced cell) at the specified address. */
73 : void ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
74 :
75 : void LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable);
76 :
77 : private:
78 : typedef boost::shared_ptr< XclImpCrn > XclImpCrnRef;
79 : typedef std::vector< XclImpCrnRef > XclImpCrnList;
80 :
81 : XclImpCrnList maCrnList; /// List of CRN records (cached cell values).
82 : OUString maTabName; /// Name of the external sheet.
83 : };
84 :
85 : // External document (SUPBOOK) ================================================
86 :
87 : /** This class represents an external linked document (record SUPBOOK).
88 : @descr Contains a list of all referenced sheets in the document. */
89 98 : class XclImpSupbook : protected XclImpRoot
90 : {
91 : public:
92 : /** Reads the SUPBOOK record from stream. */
93 : explicit XclImpSupbook( XclImpStream& rStrm );
94 :
95 : /** Reads an XCT record (count of following CRNs and current sheet). */
96 : void ReadXct( XclImpStream& rStrm );
97 : /** Reads a CRN record (external referenced cell). */
98 : void ReadCrn( XclImpStream& rStrm );
99 : /** Reads an EXTERNNAME record. */
100 : void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
101 :
102 : /** Returns the SUPBOOK record type. */
103 1165 : inline XclSupbookType GetType() const { return meType; }
104 :
105 : /** Returns the URL of the external document. */
106 2 : inline const OUString& GetXclUrl() const { return maXclUrl; }
107 :
108 : /** Returns the external name specified by an index from the Excel document (one-based). */
109 : const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
110 : /** Tries to decode the URL to OLE or DDE link components.
111 : @descr For DDE links: Decodes to application name and topic.
112 : For OLE object links: Decodes to class name and document URL.
113 : @return true = decoding was successful, returned strings are valid (not empty). */
114 : bool GetLinkData( OUString& rApplic, OUString& rDoc ) const;
115 : /** Returns the specified macro name (1-based) or an empty string on error. */
116 : const OUString& GetMacroName( sal_uInt16 nXclNameIdx ) const;
117 :
118 : const OUString& GetTabName( sal_uInt16 nXtiTab ) const;
119 :
120 : sal_uInt16 GetTabCount() const;
121 :
122 : void LoadCachedValues();
123 :
124 : svl::SharedStringPool& GetSharedStringPool();
125 :
126 : private:
127 : typedef boost::ptr_vector< XclImpSupbookTab > XclImpSupbookTabList;
128 : typedef boost::ptr_vector< XclImpExtName > XclImpExtNameList;
129 :
130 : XclImpSupbookTabList maSupbTabList; /// All sheet names of the document.
131 : XclImpExtNameList maExtNameList; /// All external names of the document.
132 : OUString maXclUrl; /// URL of the external document (Excel mode).
133 : XclSupbookType meType; /// Type of the supbook record.
134 : sal_uInt16 mnSBTab; /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
135 : };
136 :
137 : // Import link manager ========================================================
138 :
139 : /** Contains the SUPBOOK index and sheet indexes of an external link.
140 : @descr It is possible to enter a formula like =SUM(Sheet1:Sheet3!A1),
141 : therefore here occurs a sheet range. */
142 : struct XclImpXti
143 : {
144 : sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
145 : sal_uInt16 mnSBTabFirst; /// Index to the first sheet of the range in the SUPBOOK.
146 : sal_uInt16 mnSBTabLast; /// Index to the last sheet of the range in the SUPBOOK.
147 80 : inline explicit XclImpXti() : mnSupbook( SAL_MAX_UINT16 ), mnSBTabFirst( SAL_MAX_UINT16 ), mnSBTabLast( SAL_MAX_UINT16 ) {}
148 : };
149 :
150 80 : inline XclImpStream& operator>>( XclImpStream& rStrm, XclImpXti& rXti )
151 : {
152 80 : rXti.mnSupbook = rStrm.ReaduInt16();
153 80 : rXti.mnSBTabFirst = rStrm.ReaduInt16();
154 80 : rXti.mnSBTabLast = rStrm.ReaduInt16();
155 80 : return rStrm;
156 : }
157 :
158 : /** Implementation of the link manager. */
159 162 : class XclImpLinkManagerImpl : protected XclImpRoot
160 : {
161 : public:
162 : explicit XclImpLinkManagerImpl( const XclImpRoot& rRoot );
163 :
164 : /** Reads the EXTERNSHEET record. */
165 : void ReadExternsheet( XclImpStream& rStrm );
166 : /** Reads a SUPBOOK record. */
167 : void ReadSupbook( XclImpStream& rStrm );
168 : /** Reads an XCT record and appends it to the current SUPBOOK. */
169 : void ReadXct( XclImpStream& rStrm );
170 : /** Reads a CRN record and appends it to the current SUPBOOK. */
171 : void ReadCrn( XclImpStream& rStrm );
172 : /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
173 : void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
174 :
175 : /** Returns true, if the specified XTI entry contains an internal reference. */
176 : bool IsSelfRef( sal_uInt16 nXtiIndex ) const;
177 : /** Returns the Calc sheet index range of the specified XTI entry.
178 : @return true = XTI data found, returned sheet index range is valid. */
179 : bool GetScTabRange(
180 : SCTAB& rnFirstScTab, SCTAB& rnLastScTab,
181 : sal_uInt16 nXtiIndex ) const;
182 : /** Returns the specified external name or 0 on error. */
183 : const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
184 :
185 : /** Returns the absolute file URL of a supporting workbook specified by
186 : the index. */
187 : const OUString* GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
188 :
189 : const OUString& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
190 :
191 : /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
192 : @descr For DDE links: Decodes to application name and topic.
193 : For OLE object links: Decodes to class name and document URL.
194 : @return true = decoding was successful, returned strings are valid (not empty). */
195 : bool GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const;
196 : /** Returns the specified macro name or an empty string on error. */
197 : const OUString& GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
198 :
199 : private:
200 : /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
201 : const XclImpXti* GetXti( sal_uInt16 nXtiIndex ) const;
202 : /** Returns the specified SUPBOOK (external document). */
203 : const XclImpSupbook* GetSupbook( sal_uInt16 nXtiIndex ) const;
204 :
205 : void LoadCachedValues();
206 :
207 : private:
208 : typedef ::std::vector< XclImpXti > XclImpXtiVector;
209 : typedef boost::ptr_vector< XclImpSupbook > XclImpSupbookList;
210 :
211 : XclImpXtiVector maXtiList; /// List of all XTI structures.
212 : XclImpSupbookList maSupbookList; /// List of external documents.
213 : };
214 :
215 : // *** Implementation ***
216 :
217 : // Excel sheet indexes ========================================================
218 :
219 : // original Excel sheet names -------------------------------------------------
220 :
221 219 : void XclImpTabInfo::AppendXclTabName( const OUString& rXclTabName, SCTAB nScTab )
222 : {
223 219 : maTabNames[ rXclTabName ] = nScTab;
224 219 : }
225 :
226 0 : void XclImpTabInfo::InsertScTab( SCTAB nScTab )
227 : {
228 0 : for( XclTabNameMap::iterator aIt = maTabNames.begin(), aEnd = maTabNames.end(); aIt != aEnd; ++aIt )
229 0 : if( aIt->second >= nScTab )
230 0 : ++aIt->second;
231 0 : }
232 :
233 2 : SCTAB XclImpTabInfo::GetScTabFromXclName( const OUString& rXclTabName ) const
234 : {
235 2 : XclTabNameMap::const_iterator aIt = maTabNames.find( rXclTabName );
236 2 : return (aIt != maTabNames.end()) ? aIt->second : SCTAB_INVALID;
237 : }
238 :
239 : // record creation order - TABID record ---------------------------------------
240 :
241 78 : void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
242 : {
243 : OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
244 78 : if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
245 : {
246 78 : rStrm.EnableDecryption();
247 78 : sal_Size nReadCount = rStrm.GetRecLeft() / 2;
248 : OSL_ENSURE( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
249 78 : maTabIdVec.clear();
250 78 : maTabIdVec.reserve( nReadCount );
251 296 : for( sal_Size nIndex = 0; rStrm.IsValid() && (nIndex < nReadCount); ++nIndex )
252 : // zero index is not allowed in BIFF8, but it seems that it occurs in real life
253 218 : maTabIdVec.push_back( rStrm.ReaduInt16() );
254 : }
255 78 : }
256 :
257 26 : sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMaxTabId ) const
258 : {
259 26 : sal_uInt16 nReturn = 0;
260 26 : for( ScfUInt16Vec::const_iterator aIt = maTabIdVec.begin(), aEnd = maTabIdVec.end(); aIt != aEnd; ++aIt )
261 : {
262 26 : sal_uInt16 nValue = *aIt;
263 26 : if( nValue == nCreatedId )
264 26 : return nReturn;
265 0 : if( nValue <= nMaxTabId )
266 0 : ++nReturn;
267 : }
268 0 : return 0;
269 : }
270 :
271 : // External names =============================================================
272 :
273 0 : XclImpExtName::MOper::MOper(svl::SharedStringPool& rPool, XclImpStream& rStrm) :
274 0 : mxCached(new ScMatrix(0,0))
275 : {
276 0 : SCSIZE nLastCol = rStrm.ReaduInt8();
277 0 : SCSIZE nLastRow = rStrm.ReaduInt16();
278 :
279 : //assuming worse case scenario of nOp + one byte unistring len
280 0 : const size_t nMinRecordSize = 2;
281 0 : const size_t nMaxRows = rStrm.GetRecLeft() / (nMinRecordSize * (nLastCol+1));
282 0 : if (nLastRow >= nMaxRows)
283 : {
284 : SAL_WARN("sc", "Parsing error: " << nMaxRows <<
285 : " max possible rows, but " << nLastRow << " index claimed, truncating");
286 0 : nLastRow = nMaxRows-1;
287 : }
288 :
289 0 : mxCached->Resize(nLastCol+1, nLastRow+1);
290 0 : for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow)
291 : {
292 0 : for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol)
293 : {
294 : sal_uInt8 nOp;
295 0 : nOp = rStrm.ReaduInt8();
296 0 : switch (nOp)
297 : {
298 : case 0x01:
299 : {
300 0 : double fVal = rStrm.ReadDouble();
301 0 : mxCached->PutDouble(fVal, nCol, nRow);
302 : }
303 0 : break;
304 : case 0x02:
305 : {
306 0 : OUString aStr = rStrm.ReadUniString();
307 0 : mxCached->PutString(rPool.intern(aStr), nCol, nRow);
308 : }
309 0 : break;
310 : case 0x04:
311 : {
312 0 : bool bVal = rStrm.ReaduInt8();
313 0 : mxCached->PutBoolean(bVal, nCol, nRow);
314 0 : rStrm.Ignore(7);
315 : }
316 0 : break;
317 : case 0x10:
318 : {
319 0 : sal_uInt8 nErr = rStrm.ReaduInt8();
320 : // TODO: Map the error code from xls to calc.
321 0 : mxCached->PutError(nErr, nCol, nRow);
322 0 : rStrm.Ignore(7);
323 : }
324 0 : break;
325 : default:
326 0 : rStrm.Ignore(8);
327 : }
328 : }
329 : }
330 0 : }
331 :
332 0 : const ScMatrix& XclImpExtName::MOper::GetCache() const
333 : {
334 0 : return *mxCached;
335 : }
336 :
337 0 : XclImpExtName::XclImpExtName( XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv )
338 : : mpMOper(NULL)
339 0 : , mnStorageId(0)
340 : {
341 0 : sal_uInt16 nFlags(0);
342 0 : sal_uInt8 nLen(0);
343 :
344 0 : nFlags = rStrm.ReaduInt16();
345 0 : mnStorageId = rStrm.ReaduInt32();
346 0 : nLen = rStrm.ReaduInt8();
347 0 : maName = rStrm.ReadUniString( nLen );
348 0 : if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
349 : {
350 0 : if( eSubType == EXC_SBTYPE_ADDIN )
351 : {
352 0 : meType = xlExtAddIn;
353 0 : maName = XclImpRoot::GetScAddInName( maName );
354 : }
355 0 : else if ( (eSubType == EXC_SBTYPE_EUROTOOL) &&
356 0 : maName.equalsIgnoreAsciiCase( "EUROCONVERT" ) )
357 0 : meType = xlExtEuroConvert;
358 : else
359 : {
360 0 : meType = xlExtName;
361 0 : maName = ScfTools::ConvertToScDefinedName( maName );
362 : }
363 : }
364 : else
365 : {
366 0 : meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
367 : }
368 :
369 0 : switch (meType)
370 : {
371 : case xlExtDDE:
372 0 : if (rStrm.GetRecLeft() > 1)
373 0 : mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm));
374 0 : break;
375 : case xlExtName:
376 : // TODO: For now, only global external names are supported. In future
377 : // we should extend this to supporting per-sheet external names.
378 0 : if (mnStorageId == 0)
379 : {
380 0 : if (pFormulaConv)
381 : {
382 0 : const ScTokenArray* pArray = NULL;
383 : sal_uInt16 nFmlaLen;
384 0 : nFmlaLen = rStrm.ReaduInt16();
385 0 : vector<OUString> aTabNames;
386 0 : sal_uInt16 nCount = rSupbook.GetTabCount();
387 0 : aTabNames.reserve(nCount);
388 0 : for (sal_uInt16 i = 0; i < nCount; ++i)
389 0 : aTabNames.push_back(rSupbook.GetTabName(i));
390 :
391 0 : pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
392 0 : if (pArray)
393 0 : mxArray.reset(pArray->Clone());
394 : }
395 : }
396 0 : break;
397 : case xlExtOLE:
398 0 : mpMOper = new MOper(rSupbook.GetSharedStringPool(), rStrm);
399 0 : break;
400 : default:
401 : ;
402 : }
403 0 : }
404 :
405 0 : XclImpExtName::~XclImpExtName()
406 : {
407 0 : delete mpMOper;
408 0 : }
409 :
410 0 : void XclImpExtName::CreateDdeData( ScDocument& rDoc, const OUString& rApplic, const OUString& rTopic ) const
411 : {
412 0 : ScMatrixRef xResults;
413 0 : if( mxDdeMatrix.get() )
414 0 : xResults = mxDdeMatrix->CreateScMatrix(rDoc.GetSharedStringPool());
415 0 : rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
416 0 : }
417 :
418 0 : void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
419 : {
420 0 : if (!mxArray.get())
421 0 : return;
422 :
423 0 : ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
424 0 : pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
425 : }
426 :
427 : namespace {
428 :
429 : /**
430 : * Decompose the name into sheet name and range name. An OLE link name is
431 : * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
432 : * notation.
433 : */
434 0 : bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange)
435 : {
436 0 : sal_Int32 n = rName.getLength();
437 0 : const sal_Unicode* p = rName.getStr();
438 0 : OUStringBuffer aBuf;
439 0 : bool bInSheet = true;
440 0 : for (sal_Int32 i = 0; i < n; ++i, ++p)
441 : {
442 0 : if (i == 0)
443 : {
444 : // first character must be '!'.
445 0 : if (*p != '!')
446 0 : return false;
447 0 : continue;
448 : }
449 :
450 0 : if (*p == '!')
451 : {
452 : // sheet name to range separator.
453 0 : if (!bInSheet)
454 0 : return false;
455 0 : rSheet = aBuf.makeStringAndClear();
456 0 : bInSheet = false;
457 0 : continue;
458 : }
459 :
460 0 : aBuf.append(*p);
461 : }
462 :
463 0 : rRange = aBuf.makeStringAndClear();
464 0 : return true;
465 : }
466 :
467 : }
468 :
469 0 : bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl,
470 : sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const
471 : {
472 0 : if (!mpMOper)
473 0 : return false;
474 :
475 0 : OUString aSheet, aRangeStr;
476 0 : if (!extractSheetAndRange(maName, aSheet, aRangeStr))
477 0 : return false;
478 :
479 0 : ScRange aRange;
480 0 : sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
481 0 : if ((nRes & SCA_VALID) != SCA_VALID)
482 0 : return false;
483 :
484 0 : if (aRange.aStart.Tab() != aRange.aEnd.Tab())
485 : // We don't support multi-sheet range for this.
486 0 : return false;
487 :
488 0 : const ScMatrix& rCache = mpMOper->GetCache();
489 : SCSIZE nC, nR;
490 0 : rCache.GetDimensions(nC, nR);
491 0 : if (!nC || !nR)
492 : // cache matrix is empty.
493 0 : return false;
494 :
495 0 : ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
496 0 : sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
497 0 : ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL);
498 0 : if (!xTab)
499 : // cache table creation failed.
500 0 : return false;
501 :
502 0 : xTab->setWholeTableCached();
503 0 : for (SCSIZE i = 0; i < nR; ++i)
504 : {
505 0 : for (SCSIZE j = 0; j < nC; ++j)
506 : {
507 0 : SCCOL nCol = aRange.aStart.Col() + j;
508 0 : SCROW nRow = aRange.aStart.Row() + i;
509 :
510 0 : ScMatrixValue aVal = rCache.Get(j, i);
511 0 : switch (aVal.nType)
512 : {
513 : case SC_MATVAL_BOOLEAN:
514 : {
515 0 : bool b = aVal.GetBoolean();
516 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
517 0 : xTab->setCell(nCol, nRow, pToken, 0, false);
518 : }
519 0 : break;
520 : case SC_MATVAL_VALUE:
521 : {
522 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal));
523 0 : xTab->setCell(nCol, nRow, pToken, 0, false);
524 : }
525 0 : break;
526 : case SC_MATVAL_STRING:
527 : {
528 0 : const svl::SharedString aStr( aVal.GetString());
529 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(aStr));
530 0 : xTab->setCell(nCol, nRow, pToken, 0, false);
531 : }
532 0 : break;
533 : default:
534 : ;
535 : }
536 0 : }
537 : }
538 :
539 0 : rFileId = nFileId;
540 0 : rTabName = aSheet;
541 0 : rRange = aRange;
542 0 : return true;
543 : }
544 :
545 0 : bool XclImpExtName::HasFormulaTokens() const
546 : {
547 0 : return (mxArray.get() != NULL);
548 : }
549 :
550 : // Cached external cells ======================================================
551 :
552 2 : XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
553 : XclImpCachedValue( rStrm ),
554 2 : maXclPos( rXclPos )
555 : {
556 2 : }
557 :
558 : // Sheet in an external document ==============================================
559 :
560 2 : XclImpSupbookTab::XclImpSupbookTab( const OUString& rTabName ) :
561 2 : maTabName( rTabName )
562 : {
563 2 : }
564 :
565 2 : XclImpSupbookTab::~XclImpSupbookTab()
566 : {
567 2 : }
568 :
569 2 : void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
570 : {
571 2 : XclImpCrnRef crnRef( new XclImpCrn(rStrm, rXclPos) );
572 2 : maCrnList.push_back( crnRef );
573 2 : }
574 :
575 2 : void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable)
576 : {
577 2 : if (maCrnList.empty())
578 2 : return;
579 :
580 4 : for (XclImpCrnList::iterator itCrnRef = maCrnList.begin(); itCrnRef != maCrnList.end(); ++itCrnRef)
581 : {
582 2 : const XclImpCrn* const pCrn = itCrnRef->get();
583 2 : const XclAddress& rAddr = pCrn->GetAddress();
584 2 : switch (pCrn->GetType())
585 : {
586 : case EXC_CACHEDVAL_BOOL:
587 : {
588 0 : bool b = pCrn->GetBool();
589 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
590 0 : pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
591 : }
592 0 : break;
593 : case EXC_CACHEDVAL_DOUBLE:
594 : {
595 0 : double f = pCrn->GetValue();
596 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(f));
597 0 : pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
598 : }
599 0 : break;
600 : case EXC_CACHEDVAL_ERROR:
601 : {
602 0 : double fError = XclTools::ErrorToDouble( pCrn->GetXclError() );
603 0 : ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(fError));
604 0 : pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
605 : }
606 0 : break;
607 : case EXC_CACHEDVAL_STRING:
608 : {
609 2 : const OUString& rStr = pCrn->GetString();
610 2 : ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
611 2 : pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
612 : }
613 2 : break;
614 : default:
615 : ;
616 : }
617 : }
618 : }
619 :
620 : // External document (SUPBOOK) ================================================
621 :
622 49 : XclImpSupbook::XclImpSupbook( XclImpStream& rStrm ) :
623 49 : XclImpRoot( rStrm.GetRoot() ),
624 : meType( EXC_SBTYPE_UNKNOWN ),
625 49 : mnSBTab( EXC_TAB_DELETED )
626 : {
627 : sal_uInt16 nSBTabCnt;
628 49 : nSBTabCnt = rStrm.ReaduInt16();
629 :
630 49 : if( rStrm.GetRecLeft() == 2 )
631 : {
632 47 : switch( rStrm.ReaduInt16() )
633 : {
634 47 : case EXC_SUPB_SELF: meType = EXC_SBTYPE_SELF; break;
635 0 : case EXC_SUPB_ADDIN: meType = EXC_SBTYPE_ADDIN; break;
636 : default: OSL_FAIL( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
637 : }
638 96 : return;
639 : }
640 :
641 2 : OUString aEncUrl( rStrm.ReadUniString() );
642 2 : bool bSelf = false;
643 2 : XclImpUrlHelper::DecodeUrl( maXclUrl, bSelf, GetRoot(), aEncUrl );
644 :
645 2 : if( maXclUrl.equalsIgnoreAsciiCase( "\010EUROTOOL.XLA" ) )
646 : {
647 0 : meType = EXC_SBTYPE_EUROTOOL;
648 0 : maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
649 : }
650 2 : else if( nSBTabCnt )
651 : {
652 2 : meType = EXC_SBTYPE_EXTERN;
653 :
654 : //assuming all empty strings with just len header of 0
655 2 : const size_t nMinRecordSize = sizeof(sal_Int16);
656 2 : const size_t nMaxRecords = rStrm.GetRecLeft() / nMinRecordSize;
657 2 : if (nSBTabCnt > nMaxRecords)
658 : {
659 : SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
660 : " max possible entries, but " << nSBTabCnt << " claimed, truncating");
661 0 : nSBTabCnt = nMaxRecords;
662 : }
663 :
664 4 : for( sal_uInt16 nSBTab = 0; nSBTab < nSBTabCnt; ++nSBTab )
665 : {
666 2 : OUString aTabName( rStrm.ReadUniString() );
667 2 : maSupbTabList.push_back( new XclImpSupbookTab( aTabName ) );
668 2 : }
669 : }
670 : else
671 : {
672 0 : meType = EXC_SBTYPE_SPECIAL;
673 : // create dummy list entry
674 0 : maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
675 2 : }
676 : }
677 :
678 2 : void XclImpSupbook::ReadXct( XclImpStream& rStrm )
679 : {
680 2 : rStrm.Ignore( 2 );
681 2 : mnSBTab = rStrm.ReaduInt16();
682 2 : }
683 :
684 2 : void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
685 : {
686 2 : if (mnSBTab >= maSupbTabList.size())
687 2 : return;
688 2 : XclImpSupbookTab& rSbTab = maSupbTabList[mnSBTab];
689 : sal_uInt8 nXclColLast, nXclColFirst;
690 : sal_uInt16 nXclRow;
691 2 : nXclColLast = rStrm.ReaduInt8();
692 2 : nXclColFirst = rStrm.ReaduInt8();
693 2 : nXclRow = rStrm.ReaduInt16();
694 :
695 4 : for( sal_uInt8 nXclCol = nXclColFirst; (nXclCol <= nXclColLast) && (rStrm.GetRecLeft() > 1); ++nXclCol )
696 2 : rSbTab.ReadCrn( rStrm, XclAddress( nXclCol, nXclRow ) );
697 : }
698 :
699 0 : void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
700 : {
701 0 : maExtNameList.push_back( new XclImpExtName( *this, rStrm, meType, pFormulaConv ) );
702 0 : }
703 :
704 0 : const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
705 : {
706 : OSL_ENSURE( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" );
707 0 : if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size())
708 0 : return NULL;
709 0 : return &maExtNameList[nXclIndex-1];
710 : }
711 :
712 0 : bool XclImpSupbook::GetLinkData( OUString& rApplic, OUString& rTopic ) const
713 : {
714 0 : return (meType == EXC_SBTYPE_SPECIAL) && XclImpUrlHelper::DecodeLink( rApplic, rTopic, maXclUrl );
715 : }
716 :
717 1 : const OUString& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
718 : {
719 : OSL_ENSURE( nXclNameIdx > 0, "XclImpSupbook::GetMacroName - index must be >0" );
720 1 : const XclImpName* pName = (meType == EXC_SBTYPE_SELF) ? GetNameManager().GetName( nXclNameIdx ) : 0;
721 1 : return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_OUSTRING;
722 : }
723 :
724 2 : const OUString& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
725 : {
726 2 : if (nXtiTab >= maSupbTabList.size())
727 0 : return EMPTY_OUSTRING;
728 2 : return maSupbTabList[nXtiTab].GetTabName();
729 : }
730 :
731 0 : sal_uInt16 XclImpSupbook::GetTabCount() const
732 : {
733 0 : return ulimit_cast<sal_uInt16>(maSupbTabList.size());
734 : }
735 :
736 49 : void XclImpSupbook::LoadCachedValues()
737 : {
738 49 : if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0 || !GetDocShell())
739 96 : return;
740 :
741 2 : OUString aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
742 :
743 2 : ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
744 2 : sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
745 :
746 4 : for (XclImpSupbookTabList::iterator itTab = maSupbTabList.begin(); itTab != maSupbTabList.end(); ++itTab)
747 : {
748 2 : const OUString& rTabName = itTab->GetTabName();
749 2 : ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
750 2 : itTab->LoadCachedValues(pCacheTable);
751 2 : pCacheTable->setWholeTableCached();
752 4 : }
753 : }
754 :
755 0 : svl::SharedStringPool& XclImpSupbook::GetSharedStringPool()
756 : {
757 0 : return GetDoc().GetSharedStringPool();
758 : }
759 :
760 : // Import link manager ========================================================
761 :
762 81 : XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot& rRoot ) :
763 81 : XclImpRoot( rRoot )
764 : {
765 81 : }
766 :
767 47 : void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
768 : {
769 : sal_uInt16 nXtiCount;
770 47 : nXtiCount = rStrm.ReaduInt16();
771 : OSL_ENSURE( static_cast< sal_Size >( nXtiCount * 6 ) == rStrm.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
772 47 : nXtiCount = static_cast< sal_uInt16 >( ::std::min< sal_Size >( nXtiCount, rStrm.GetRecLeft() / 6 ) );
773 :
774 : /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
775 : records instead of only one as expected. Surprisingly, Excel seems to
776 : insert the entries of the second record before the entries of the first
777 : record. */
778 47 : XclImpXtiVector aNewEntries( nXtiCount );
779 127 : for( XclImpXtiVector::iterator aIt = aNewEntries.begin(), aEnd = aNewEntries.end(); rStrm.IsValid() && (aIt != aEnd); ++aIt )
780 80 : rStrm >> *aIt;
781 47 : maXtiList.insert( maXtiList.begin(), aNewEntries.begin(), aNewEntries.end() );
782 :
783 47 : LoadCachedValues();
784 47 : }
785 :
786 49 : void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
787 : {
788 49 : maSupbookList.push_back( new XclImpSupbook( rStrm ) );
789 49 : }
790 :
791 2 : void XclImpLinkManagerImpl::ReadXct( XclImpStream& rStrm )
792 : {
793 2 : if( !maSupbookList.empty() )
794 2 : maSupbookList.back().ReadXct( rStrm );
795 2 : }
796 :
797 2 : void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
798 : {
799 2 : if( !maSupbookList.empty() )
800 2 : maSupbookList.back().ReadCrn( rStrm );
801 2 : }
802 :
803 0 : void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
804 : {
805 0 : if( !maSupbookList.empty() )
806 0 : maSupbookList.back().ReadExternname( rStrm, pFormulaConv );
807 0 : }
808 :
809 1165 : bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
810 : {
811 1165 : const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
812 1165 : return pSupbook && (pSupbook->GetType() == EXC_SBTYPE_SELF);
813 : }
814 :
815 1173 : bool XclImpLinkManagerImpl::GetScTabRange(
816 : SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
817 : {
818 1173 : if( const XclImpXti* pXti = GetXti( nXtiIndex ) )
819 : {
820 1173 : if (!maSupbookList.empty() && (pXti->mnSupbook < maSupbookList.size()) )
821 : {
822 1173 : rnFirstScTab = pXti->mnSBTabFirst;
823 1173 : rnLastScTab = pXti->mnSBTabLast;
824 1173 : return true;
825 : }
826 : }
827 0 : return false;
828 : }
829 :
830 0 : const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
831 : {
832 0 : const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
833 0 : return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
834 : }
835 :
836 2 : const OUString* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
837 : {
838 2 : const XclImpSupbook* p = GetSupbook( nXtiIndex );
839 2 : if (!p)
840 0 : return NULL;
841 2 : return &p->GetXclUrl();
842 : }
843 :
844 2 : const OUString& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
845 : {
846 2 : const XclImpSupbook* p = GetSupbook(nXti);
847 2 : return p ? p->GetTabName(nXtiTab) : EMPTY_OUSTRING;
848 : }
849 :
850 0 : bool XclImpLinkManagerImpl::GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const
851 : {
852 0 : const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
853 0 : return pSupbook && pSupbook->GetLinkData( rApplic, rTopic );
854 : }
855 :
856 1 : const OUString& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
857 : {
858 1 : const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
859 1 : return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_OUSTRING;
860 : }
861 :
862 2343 : const XclImpXti* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex ) const
863 : {
864 2343 : return (nXtiIndex < maXtiList.size()) ? &maXtiList[ nXtiIndex ] : 0;
865 : }
866 :
867 1170 : const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex ) const
868 : {
869 1170 : if ( maSupbookList.empty() )
870 0 : return NULL;
871 1170 : const XclImpXti* pXti = GetXti( nXtiIndex );
872 1170 : if (!pXti || pXti->mnSupbook >= maSupbookList.size())
873 0 : return NULL;
874 1170 : return &(maSupbookList.at( pXti->mnSupbook ));
875 : }
876 :
877 47 : void XclImpLinkManagerImpl::LoadCachedValues()
878 : {
879 : // Read all CRN records which can be accessed via XclImpSupbook, and store
880 : // the cached values to the external reference manager.
881 96 : for (XclImpSupbookList::iterator itSupbook = maSupbookList.begin(); itSupbook != maSupbookList.end(); ++itSupbook)
882 49 : itSupbook->LoadCachedValues();
883 47 : }
884 :
885 81 : XclImpLinkManager::XclImpLinkManager( const XclImpRoot& rRoot ) :
886 : XclImpRoot( rRoot ),
887 81 : mxImpl( new XclImpLinkManagerImpl( rRoot ) )
888 : {
889 81 : }
890 :
891 162 : XclImpLinkManager::~XclImpLinkManager()
892 : {
893 162 : }
894 :
895 47 : void XclImpLinkManager::ReadExternsheet( XclImpStream& rStrm )
896 : {
897 47 : mxImpl->ReadExternsheet( rStrm );
898 47 : }
899 :
900 49 : void XclImpLinkManager::ReadSupbook( XclImpStream& rStrm )
901 : {
902 49 : mxImpl->ReadSupbook( rStrm );
903 49 : }
904 :
905 2 : void XclImpLinkManager::ReadXct( XclImpStream& rStrm )
906 : {
907 2 : mxImpl->ReadXct( rStrm );
908 2 : }
909 :
910 2 : void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
911 : {
912 2 : mxImpl->ReadCrn( rStrm );
913 2 : }
914 :
915 0 : void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
916 : {
917 0 : mxImpl->ReadExternname( rStrm, pFormulaConv );
918 0 : }
919 :
920 1165 : bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
921 : {
922 1165 : return mxImpl->IsSelfRef( nXtiIndex );
923 : }
924 :
925 1173 : bool XclImpLinkManager::GetScTabRange(
926 : SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
927 : {
928 1173 : return mxImpl->GetScTabRange( rnFirstScTab, rnLastScTab, nXtiIndex );
929 : }
930 :
931 0 : const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
932 : {
933 0 : return mxImpl->GetExternName( nXtiIndex, nExtName );
934 : }
935 :
936 2 : const OUString* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
937 : {
938 2 : return mxImpl->GetSupbookUrl(nXtiIndex);
939 : }
940 :
941 2 : const OUString& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
942 : {
943 2 : return mxImpl->GetSupbookTabName(nXti, nXtiTab);
944 : }
945 :
946 0 : bool XclImpLinkManager::GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const
947 : {
948 0 : return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
949 : }
950 :
951 1 : const OUString& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
952 : {
953 1 : return mxImpl->GetMacroName( nExtSheet, nExtName );
954 30 : }
955 :
956 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|