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