use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / xilink.cxx
blob987d0185042ef2d70ce528adc694911e177f3f6e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <utility>
21 #include <xilink.hxx>
22 #include <document.hxx>
23 #include <docsh.hxx>
24 #include <scextopt.hxx>
25 #include <xistream.hxx>
26 #include <xihelper.hxx>
27 #include <xiname.hxx>
28 #include <xltools.hxx>
29 #include <excform.hxx>
30 #include <tokenarray.hxx>
31 #include <externalrefmgr.hxx>
32 #include <scmatrix.hxx>
33 #include <svl/sharedstringpool.hxx>
34 #include <sal/log.hxx>
36 #include <vector>
37 #include <memory>
39 // *** Helper classes ***
41 // Cached external cells ======================================================
43 namespace {
45 /**
46 * Contains the address and value of an external referenced cell.
47 * Note that this is non-copyable, so cannot be used in most stl/boost containers.
49 class XclImpCrn : public XclImpCachedValue
51 public:
52 /** Reads a cached value and stores it with its cell address. */
53 explicit XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
55 const XclAddress& GetAddress() const { return maXclPos;}
57 private:
58 XclAddress maXclPos; /// Excel position of the cached cell.
61 // Sheet in an external document ==============================================
63 /** Contains the name and sheet index of one sheet in an external document. */
64 class XclImpSupbookTab
66 public:
67 /** Stores the sheet name and marks the sheet index as invalid.
68 The sheet index is set while creating the Calc sheet with CreateTable(). */
69 explicit XclImpSupbookTab( OUString aTabName );
71 const OUString& GetTabName() const { return maTabName; }
73 /** Reads a CRN record (external referenced cell) at the specified address. */
74 void ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
76 void LoadCachedValues( const ScExternalRefCache::TableTypeRef& pCacheTable,
77 svl::SharedStringPool& rPool );
79 private:
80 typedef std::shared_ptr< XclImpCrn > XclImpCrnRef;
82 std::vector< XclImpCrnRef > maCrnList; /// List of CRN records (cached cell values).
83 OUString maTabName; /// Name of the external sheet.
88 // External document (SUPBOOK) ================================================
90 /** This class represents an external linked document (record SUPBOOK).
91 @descr Contains a list of all referenced sheets in the document. */
92 class XclImpSupbook : protected XclImpRoot
94 public:
95 /** Reads the SUPBOOK record from stream. */
96 explicit XclImpSupbook( XclImpStream& rStrm );
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 );
105 /** Returns the SUPBOOK record type. */
106 XclSupbookType GetType() const { return meType; }
108 /** Returns the URL of the external document. */
109 const OUString& GetXclUrl() const { return maXclUrl; }
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( OUString& rApplic, OUString& rDoc ) const;
118 /** Returns the specified macro name (1-based) or an empty string on error. */
119 OUString GetMacroName( sal_uInt16 nXclNameIdx ) const;
121 const OUString & GetTabName( sal_uInt16 nXtiTab ) const;
123 sal_uInt16 GetTabCount() const;
125 void LoadCachedValues();
127 svl::SharedStringPool& GetSharedStringPool();
129 private:
131 std::vector< std::unique_ptr<XclImpSupbookTab> >
132 maSupbTabList; /// All sheet names of the document.
133 std::vector< std::unique_ptr<XclImpExtName> >
134 maExtNameList; /// All external names of the document.
135 OUString maXclUrl; /// URL of the external document (Excel mode).
136 XclSupbookType meType; /// Type of the supbook record.
137 sal_uInt16 mnSBTab; /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
140 // Import link manager ========================================================
142 namespace {
144 /** Contains the SUPBOOK index and sheet indexes of an external link.
145 @descr It is possible to enter a formula like =SUM(Sheet1:Sheet3!A1),
146 therefore here occurs a sheet range. */
147 struct XclImpXti
149 sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
150 sal_uInt16 mnSBTabFirst; /// Index to the first sheet of the range in the SUPBOOK.
151 sal_uInt16 mnSBTabLast; /// Index to the last sheet of the range in the SUPBOOK.
152 explicit XclImpXti() : mnSupbook( SAL_MAX_UINT16 ), mnSBTabFirst( SAL_MAX_UINT16 ), mnSBTabLast( SAL_MAX_UINT16 ) {}
155 XclImpStream& operator>>( XclImpStream& rStrm, XclImpXti& rXti )
157 rXti.mnSupbook = rStrm.ReaduInt16();
158 rXti.mnSBTabFirst = rStrm.ReaduInt16();
159 rXti.mnSBTabLast = rStrm.ReaduInt16();
160 return rStrm;
165 /** Implementation of the link manager. */
166 class XclImpLinkManagerImpl : protected XclImpRoot
168 public:
169 explicit XclImpLinkManagerImpl( const XclImpRoot& rRoot );
171 /** Reads the EXTERNSHEET record. */
172 void ReadExternsheet( XclImpStream& rStrm );
173 /** Reads a SUPBOOK record. */
174 void ReadSupbook( XclImpStream& rStrm );
175 /** Reads an XCT record and appends it to the current SUPBOOK. */
176 void ReadXct( XclImpStream& rStrm );
177 /** Reads a CRN record and appends it to the current SUPBOOK. */
178 void ReadCrn( XclImpStream& rStrm );
179 /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
180 void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv );
182 /** Returns true, if the specified XTI entry contains an internal reference. */
183 bool IsSelfRef( sal_uInt16 nXtiIndex ) const;
184 /** Returns the Calc sheet index range of the specified XTI entry.
185 @return true = XTI data found, returned sheet index range is valid. */
186 bool GetScTabRange(
187 SCTAB& rnFirstScTab, SCTAB& rnLastScTab,
188 sal_uInt16 nXtiIndex ) const;
189 /** Returns the specified external name or 0 on error. */
190 const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
192 /** Returns the absolute file URL of a supporting workbook specified by
193 the index. */
194 const OUString* GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
196 OUString GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
198 /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
199 @descr For DDE links: Decodes to application name and topic.
200 For OLE object links: Decodes to class name and document URL.
201 @return true = decoding was successful, returned strings are valid (not empty). */
202 bool GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const;
203 /** Returns the specified macro name or an empty string on error. */
204 OUString GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
206 private:
207 /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
208 const XclImpXti* GetXti( sal_uInt16 nXtiIndex ) const;
209 /** Returns the specified SUPBOOK (external document). */
210 const XclImpSupbook* GetSupbook( sal_uInt16 nXtiIndex ) const;
212 void LoadCachedValues();
214 private:
215 typedef std::vector< XclImpXti > XclImpXtiVector;
217 XclImpXtiVector maXtiList; /// List of all XTI structures.
218 std::vector< std::unique_ptr<XclImpSupbook> >
219 maSupbookList; /// List of external documents.
222 // *** Implementation ***
224 // Excel sheet indexes ========================================================
226 // original Excel sheet names -------------------------------------------------
228 void XclImpTabInfo::AppendXclTabName( const OUString& rXclTabName, SCTAB nScTab )
230 maTabNames[ rXclTabName ] = nScTab;
233 void XclImpTabInfo::InsertScTab( SCTAB nScTab )
235 for( auto& rEntry : maTabNames )
236 if( rEntry.second >= nScTab )
237 ++rEntry.second;
240 SCTAB XclImpTabInfo::GetScTabFromXclName( const OUString& rXclTabName ) const
242 XclTabNameMap::const_iterator aIt = maTabNames.find( rXclTabName );
243 return (aIt != maTabNames.end()) ? aIt->second : SCTAB_INVALID;
246 // record creation order - TABID record ---------------------------------------
248 void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
250 OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
251 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
253 rStrm.EnableDecryption();
254 std::size_t nReadCount = rStrm.GetRecLeft() / 2;
255 OSL_ENSURE( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
256 maTabIdVec.clear();
257 maTabIdVec.reserve( nReadCount );
258 for( std::size_t nIndex = 0; rStrm.IsValid() && (nIndex < nReadCount); ++nIndex )
259 // zero index is not allowed in BIFF8, but it seems that it occurs in real life
260 maTabIdVec.push_back( rStrm.ReaduInt16() );
264 sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMaxTabId ) const
266 sal_uInt16 nReturn = 0;
267 for( sal_uInt16 nValue : maTabIdVec )
269 if( nValue == nCreatedId )
270 return nReturn;
271 if( nValue <= nMaxTabId )
272 ++nReturn;
274 return 0;
277 // External names =============================================================
279 XclImpExtName::MOper::MOper(svl::SharedStringPool& rPool, XclImpStream& rStrm) :
280 mxCached(new ScMatrix(0,0))
282 SCSIZE nLastCol = rStrm.ReaduInt8();
283 SCSIZE nLastRow = rStrm.ReaduInt16();
285 //assuming worst case scenario of nOp + one byte unistring len
286 const size_t nMinRecordSize = 2;
287 const size_t nMaxRows = rStrm.GetRecLeft() / (nMinRecordSize * (nLastCol+1));
288 if (nLastRow >= nMaxRows)
290 SAL_WARN("sc", "Parsing error: " << nMaxRows <<
291 " max possible rows, but " << nLastRow << " index claimed, truncating");
292 if (nMaxRows > 0)
293 nLastRow = nMaxRows-1;
294 else
295 return;
298 mxCached->Resize(nLastCol+1, nLastRow+1);
299 for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow)
301 for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol)
303 sal_uInt8 nOp;
304 nOp = rStrm.ReaduInt8();
305 switch (nOp)
307 case 0x01:
309 double fVal = rStrm.ReadDouble();
310 mxCached->PutDouble(fVal, nCol, nRow);
312 break;
313 case 0x02:
315 OUString aStr = rStrm.ReadUniString();
316 mxCached->PutString(rPool.intern(aStr), nCol, nRow);
318 break;
319 case 0x04:
321 bool bVal = rStrm.ReaduInt8();
322 mxCached->PutBoolean(bVal, nCol, nRow);
323 rStrm.Ignore(7);
325 break;
326 case 0x10:
328 sal_uInt8 nErr = rStrm.ReaduInt8();
329 // Map the error code from xls to calc.
330 mxCached->PutError(XclTools::GetScErrorCode(nErr), nCol, nRow);
331 rStrm.Ignore(7);
333 break;
334 default:
335 rStrm.Ignore(8);
341 const ScMatrix& XclImpExtName::MOper::GetCache() const
343 return *mxCached;
346 XclImpExtName::XclImpExtName( XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv )
347 : mnStorageId(0)
349 sal_uInt16 nFlags(0);
350 sal_uInt8 nLen(0);
352 nFlags = rStrm.ReaduInt16();
353 mnStorageId = rStrm.ReaduInt32();
354 nLen = rStrm.ReaduInt8();
355 maName = rStrm.ReadUniString( nLen );
356 if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
358 if( eSubType == XclSupbookType::Addin )
360 meType = xlExtAddIn;
361 maName = XclImpRoot::GetScAddInName( maName );
363 else if ( (eSubType == XclSupbookType::Eurotool) &&
364 maName.equalsIgnoreAsciiCase( "EUROCONVERT" ) )
365 meType = xlExtEuroConvert;
366 else
368 meType = xlExtName;
369 maName = ScfTools::ConvertToScDefinedName( maName );
372 else
374 meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
377 switch (meType)
379 case xlExtDDE:
380 if (rStrm.GetRecLeft() > 1)
381 mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm));
382 break;
383 case xlExtName:
384 // TODO: For now, only global external names are supported. In future
385 // we should extend this to supporting per-sheet external names.
386 if (mnStorageId == 0 && pFormulaConv)
388 std::unique_ptr<ScTokenArray> pArray;
389 sal_uInt16 nFmlaLen;
390 nFmlaLen = rStrm.ReaduInt16();
391 std::vector<OUString> aTabNames;
392 sal_uInt16 nCount = rSupbook.GetTabCount();
393 aTabNames.reserve(nCount);
394 for (sal_uInt16 i = 0; i < nCount; ++i)
395 aTabNames.push_back(rSupbook.GetTabName(i));
397 pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
398 if (pArray)
399 mxArray = std::move( pArray );
401 break;
402 case xlExtOLE:
403 moMOper.emplace( rSupbook.GetSharedStringPool(), rStrm );
404 break;
405 default:
410 XclImpExtName::~XclImpExtName()
414 void XclImpExtName::CreateDdeData( ScDocument& rDoc, const OUString& rApplic, const OUString& rTopic ) const
416 ScMatrixRef xResults;
417 if( mxDdeMatrix )
418 xResults = mxDdeMatrix->CreateScMatrix(rDoc.GetSharedStringPool());
419 rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
422 void XclImpExtName::CreateExtNameData( const ScDocument& rDoc, sal_uInt16 nFileId ) const
424 if (!mxArray)
425 return;
427 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
428 pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
431 namespace {
434 * Decompose the name into sheet name and range name. An OLE link name is
435 * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
436 * notation.
438 bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange)
440 sal_Int32 n = rName.getLength();
441 const sal_Unicode* p = rName.getStr();
442 OUStringBuffer aBuf;
443 bool bInSheet = true;
444 for (sal_Int32 i = 0; i < n; ++i, ++p)
446 if (i == 0)
448 // first character must be '!'.
449 if (*p != '!')
450 return false;
451 continue;
454 if (*p == '!')
456 // sheet name to range separator.
457 if (!bInSheet)
458 return false;
459 rSheet = aBuf.makeStringAndClear();
460 bInSheet = false;
461 continue;
464 aBuf.append(*p);
467 rRange = aBuf.makeStringAndClear();
468 return true;
473 bool XclImpExtName::CreateOleData(const ScDocument& rDoc, const OUString& rUrl,
474 sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const
476 if (!moMOper)
477 return false;
479 OUString aSheet, aRangeStr;
480 if (!extractSheetAndRange(maName, aSheet, aRangeStr))
481 return false;
483 ScRange aRange;
484 ScRefFlags nRes = aRange.ParseAny(aRangeStr, rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
485 if ((nRes & ScRefFlags::VALID) == ScRefFlags::ZERO)
486 return false;
488 if (aRange.aStart.Tab() != aRange.aEnd.Tab())
489 // We don't support multi-sheet range for this.
490 return false;
492 const ScMatrix& rCache = moMOper->GetCache();
493 SCSIZE nC, nR;
494 rCache.GetDimensions(nC, nR);
495 if (!nC || !nR)
496 // cache matrix is empty.
497 return false;
499 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
500 sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
501 ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true);
502 if (!xTab)
503 // cache table creation failed.
504 return false;
506 xTab->setWholeTableCached();
507 for (SCSIZE i = 0; i < nR; ++i)
509 for (SCSIZE j = 0; j < nC; ++j)
511 SCCOL nCol = aRange.aStart.Col() + j;
512 SCROW nRow = aRange.aStart.Row() + i;
514 ScMatrixValue aVal = rCache.Get(j, i);
515 switch (aVal.nType)
517 case ScMatValType::Boolean:
519 bool b = aVal.GetBoolean();
520 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
521 xTab->setCell(nCol, nRow, pToken, 0, false);
523 break;
524 case ScMatValType::Value:
526 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal));
527 xTab->setCell(nCol, nRow, pToken, 0, false);
529 break;
530 case ScMatValType::String:
532 ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(aVal.GetString()));
533 xTab->setCell(nCol, nRow, pToken, 0, false);
535 break;
536 default:
542 rFileId = nFileId;
543 rTabName = aSheet;
544 rRange = aRange;
545 return true;
548 bool XclImpExtName::HasFormulaTokens() const
550 return bool(mxArray);
553 // Cached external cells ======================================================
555 XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
556 XclImpCachedValue( rStrm ),
557 maXclPos( rXclPos )
561 // Sheet in an external document ==============================================
563 XclImpSupbookTab::XclImpSupbookTab( OUString aTabName ) :
564 maTabName(std::move( aTabName ))
568 void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
570 XclImpCrnRef crnRef = std::make_shared<XclImpCrn>(rStrm, rXclPos);
571 maCrnList.push_back( crnRef );
574 void XclImpSupbookTab::LoadCachedValues( const ScExternalRefCache::TableTypeRef& pCacheTable,
575 svl::SharedStringPool& rPool )
577 if (maCrnList.empty())
578 return;
580 for (const auto& rxCrn : maCrnList)
582 const XclImpCrn* const pCrn = rxCrn.get();
583 const XclAddress& rAddr = pCrn->GetAddress();
584 switch (pCrn->GetType())
586 case EXC_CACHEDVAL_BOOL:
588 bool b = pCrn->GetBool();
589 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
590 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
592 break;
593 case EXC_CACHEDVAL_DOUBLE:
595 double f = pCrn->GetValue();
596 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(f));
597 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
599 break;
600 case EXC_CACHEDVAL_ERROR:
602 double fError = XclTools::ErrorToDouble( pCrn->GetXclError() );
603 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(fError));
604 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
606 break;
607 case EXC_CACHEDVAL_STRING:
609 svl::SharedString aSS( rPool.intern( pCrn->GetString()));
610 ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken( std::move(aSS) ));
611 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
613 break;
614 default:
620 // External document (SUPBOOK) ================================================
622 XclImpSupbook::XclImpSupbook( XclImpStream& rStrm ) :
623 XclImpRoot( rStrm.GetRoot() ),
624 meType( XclSupbookType::Unknown ),
625 mnSBTab( EXC_TAB_DELETED )
627 sal_uInt16 nSBTabCnt;
628 nSBTabCnt = rStrm.ReaduInt16();
630 if( rStrm.GetRecLeft() == 2 )
632 switch( rStrm.ReaduInt16() )
634 case EXC_SUPB_SELF: meType = XclSupbookType::Self; break;
635 case EXC_SUPB_ADDIN: meType = XclSupbookType::Addin; break;
636 default: OSL_FAIL( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
638 return;
641 OUString aEncUrl( rStrm.ReadUniString() );
642 bool bSelf = false;
643 XclImpUrlHelper::DecodeUrl( maXclUrl, bSelf, GetRoot(), aEncUrl );
645 if( maXclUrl.equalsIgnoreAsciiCase( "\010EUROTOOL.XLA" ) )
647 meType = XclSupbookType::Eurotool;
648 maSupbTabList.push_back( std::make_unique<XclImpSupbookTab>( maXclUrl ) );
650 else if( nSBTabCnt )
652 meType = XclSupbookType::Extern;
654 //assuming all empty strings with just len header of 0
655 const size_t nMinRecordSize = sizeof(sal_Int16);
656 const size_t nMaxRecords = rStrm.GetRecLeft() / nMinRecordSize;
657 if (nSBTabCnt > nMaxRecords)
659 SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
660 " max possible entries, but " << nSBTabCnt << " claimed, truncating");
661 nSBTabCnt = nMaxRecords;
664 for( sal_uInt16 nSBTab = 0; nSBTab < nSBTabCnt; ++nSBTab )
666 OUString aTabName( rStrm.ReadUniString() );
667 maSupbTabList.push_back( std::make_unique<XclImpSupbookTab>( aTabName ) );
670 else
672 meType = XclSupbookType::Special;
673 // create dummy list entry
674 maSupbTabList.push_back( std::make_unique<XclImpSupbookTab>( maXclUrl ) );
678 void XclImpSupbook::ReadXct( XclImpStream& rStrm )
680 rStrm.Ignore( 2 );
681 mnSBTab = rStrm.ReaduInt16();
684 void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
686 if (mnSBTab >= maSupbTabList.size())
687 return;
688 XclImpSupbookTab& rSbTab = *maSupbTabList[mnSBTab];
689 sal_uInt8 nXclColLast, nXclColFirst;
690 sal_uInt16 nXclRow;
691 nXclColLast = rStrm.ReaduInt8();
692 nXclColFirst = rStrm.ReaduInt8();
693 nXclRow = rStrm.ReaduInt16();
695 for( sal_uInt8 nXclCol = nXclColFirst; (nXclCol <= nXclColLast) && (rStrm.GetRecLeft() > 1); ++nXclCol )
696 rSbTab.ReadCrn( rStrm, XclAddress( nXclCol, nXclRow ) );
699 void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
701 maExtNameList.push_back( std::make_unique<XclImpExtName>( *this, rStrm, meType, pFormulaConv ) );
704 const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
706 if (nXclIndex == 0)
708 SAL_WARN("sc", "XclImpSupbook::GetExternName - index must be >0");
709 return nullptr;
711 if (meType == XclSupbookType::Self || nXclIndex > maExtNameList.size())
712 return nullptr;
713 return maExtNameList[nXclIndex-1].get();
716 bool XclImpSupbook::GetLinkData( OUString& rApplic, OUString& rTopic ) const
718 return (meType == XclSupbookType::Special) && XclImpUrlHelper::DecodeLink( rApplic, rTopic, maXclUrl );
721 OUString XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
723 OSL_ENSURE( nXclNameIdx > 0, "XclImpSupbook::GetMacroName - index must be >0" );
724 const XclImpName* pName = (meType == XclSupbookType::Self) ? GetNameManager().GetName( nXclNameIdx ) : nullptr;
725 return (pName && pName->IsVBName()) ? pName->GetScName() : OUString();
728 const OUString & XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
730 if (nXtiTab >= maSupbTabList.size())
731 return EMPTY_OUSTRING;
732 return maSupbTabList[nXtiTab]->GetTabName();
735 sal_uInt16 XclImpSupbook::GetTabCount() const
737 return ulimit_cast<sal_uInt16>(maSupbTabList.size());
740 void XclImpSupbook::LoadCachedValues()
742 if (meType != XclSupbookType::Extern || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0 || !GetDocShell())
743 return;
745 OUString aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
747 ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
748 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
750 for (auto& rxTab : maSupbTabList)
752 const OUString& rTabName = rxTab->GetTabName();
753 ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
754 rxTab->LoadCachedValues( pCacheTable, GetSharedStringPool());
755 pCacheTable->setWholeTableCached();
759 svl::SharedStringPool& XclImpSupbook::GetSharedStringPool()
761 return GetDoc().GetSharedStringPool();
764 // Import link manager ========================================================
766 XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot& rRoot ) :
767 XclImpRoot( rRoot )
771 void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
773 sal_uInt16 nXtiCount;
774 nXtiCount = rStrm.ReaduInt16();
775 OSL_ENSURE( static_cast< std::size_t >( nXtiCount * 6 ) == rStrm.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
776 nXtiCount = static_cast< sal_uInt16 >( ::std::min< std::size_t >( nXtiCount, rStrm.GetRecLeft() / 6 ) );
778 /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
779 records instead of only one as expected. Surprisingly, Excel seems to
780 insert the entries of the second record before the entries of the first
781 record. */
782 XclImpXtiVector aNewEntries( nXtiCount );
783 for( auto& rNewEntry : aNewEntries )
785 if (!rStrm.IsValid())
786 break;
787 rStrm >> rNewEntry;
789 maXtiList.insert( maXtiList.begin(), aNewEntries.begin(), aNewEntries.end() );
791 LoadCachedValues();
794 void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
796 maSupbookList.push_back( std::make_unique<XclImpSupbook>( rStrm ) );
799 void XclImpLinkManagerImpl::ReadXct( XclImpStream& rStrm )
801 if( !maSupbookList.empty() )
802 maSupbookList.back()->ReadXct( rStrm );
805 void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
807 if( !maSupbookList.empty() )
808 maSupbookList.back()->ReadCrn( rStrm );
811 void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
813 if( !maSupbookList.empty() )
814 maSupbookList.back()->ReadExternname( rStrm, pFormulaConv );
817 bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
819 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
820 return pSupbook && (pSupbook->GetType() == XclSupbookType::Self);
823 bool XclImpLinkManagerImpl::GetScTabRange(
824 SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
826 if( const XclImpXti* pXti = GetXti( nXtiIndex ) )
828 if (!maSupbookList.empty() && (pXti->mnSupbook < maSupbookList.size()) )
830 rnFirstScTab = pXti->mnSBTabFirst;
831 rnLastScTab = pXti->mnSBTabLast;
832 return true;
835 return false;
838 const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
840 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
841 return pSupbook ? pSupbook->GetExternName( nExtName ) : nullptr;
844 const OUString* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
846 const XclImpSupbook* p = GetSupbook( nXtiIndex );
847 if (!p)
848 return nullptr;
849 return &p->GetXclUrl();
852 OUString XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
854 const XclImpSupbook* p = GetSupbook(nXti);
855 return p ? p->GetTabName(nXtiTab) : OUString();
858 bool XclImpLinkManagerImpl::GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const
860 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
861 return pSupbook && pSupbook->GetLinkData( rApplic, rTopic );
864 OUString XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
866 const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
867 return pSupbook ? pSupbook->GetMacroName( nExtName ) : OUString();
870 const XclImpXti* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex ) const
872 return (nXtiIndex < maXtiList.size()) ? &maXtiList[ nXtiIndex ] : nullptr;
875 const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex ) const
877 if ( maSupbookList.empty() )
878 return nullptr;
879 const XclImpXti* pXti = GetXti( nXtiIndex );
880 if (!pXti || pXti->mnSupbook >= maSupbookList.size())
881 return nullptr;
882 return maSupbookList.at( pXti->mnSupbook ).get();
885 void XclImpLinkManagerImpl::LoadCachedValues()
887 // Read all CRN records which can be accessed via XclImpSupbook, and store
888 // the cached values to the external reference manager.
889 for (auto& rxSupbook : maSupbookList)
890 rxSupbook->LoadCachedValues();
893 XclImpLinkManager::XclImpLinkManager( const XclImpRoot& rRoot ) :
894 XclImpRoot( rRoot ),
895 mxImpl( new XclImpLinkManagerImpl( rRoot ) )
899 XclImpLinkManager::~XclImpLinkManager()
903 void XclImpLinkManager::ReadExternsheet( XclImpStream& rStrm )
905 mxImpl->ReadExternsheet( rStrm );
908 void XclImpLinkManager::ReadSupbook( XclImpStream& rStrm )
910 mxImpl->ReadSupbook( rStrm );
913 void XclImpLinkManager::ReadXct( XclImpStream& rStrm )
915 mxImpl->ReadXct( rStrm );
918 void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
920 mxImpl->ReadCrn( rStrm );
923 void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
925 mxImpl->ReadExternname( rStrm, pFormulaConv );
928 bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
930 return mxImpl->IsSelfRef( nXtiIndex );
933 bool XclImpLinkManager::GetScTabRange(
934 SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
936 return mxImpl->GetScTabRange( rnFirstScTab, rnLastScTab, nXtiIndex );
939 const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
941 return mxImpl->GetExternName( nXtiIndex, nExtName );
944 const OUString* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
946 return mxImpl->GetSupbookUrl(nXtiIndex);
949 OUString XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
951 return mxImpl->GetSupbookTabName(nXti, nXtiTab);
954 bool XclImpLinkManager::GetLinkData( OUString& rApplic, OUString& rTopic, sal_uInt16 nXtiIndex ) const
956 return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
959 OUString XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
961 return mxImpl->GetMacroName( nExtSheet, nExtName );
964 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */