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