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