1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <document.hxx>
24 #include <scextopt.hxx>
25 #include <xistream.hxx>
26 #include <xihelper.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>
39 // *** Helper classes ***
41 // Cached external cells ======================================================
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
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
;}
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
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
);
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
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();
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 ========================================================
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. */
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();
165 /** Implementation of the link manager. */
166 class XclImpLinkManagerImpl
: protected XclImpRoot
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. */
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
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;
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();
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
)
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" );
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
)
271 if( nValue
<= nMaxTabId
)
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");
293 nLastRow
= nMaxRows
-1;
298 mxCached
->Resize(nLastCol
+1, nLastRow
+1);
299 for (SCSIZE nRow
= 0; nRow
<= nLastRow
; ++nRow
)
301 for (SCSIZE nCol
= 0; nCol
<= nLastCol
; ++nCol
)
304 nOp
= rStrm
.ReaduInt8();
309 double fVal
= rStrm
.ReadDouble();
310 mxCached
->PutDouble(fVal
, nCol
, nRow
);
315 OUString aStr
= rStrm
.ReadUniString();
316 mxCached
->PutString(rPool
.intern(aStr
), nCol
, nRow
);
321 bool bVal
= rStrm
.ReaduInt8();
322 mxCached
->PutBoolean(bVal
, nCol
, nRow
);
328 sal_uInt8 nErr
= rStrm
.ReaduInt8();
329 // Map the error code from xls to calc.
330 mxCached
->PutError(XclTools::GetScErrorCode(nErr
), nCol
, nRow
);
341 const ScMatrix
& XclImpExtName::MOper::GetCache() const
346 XclImpExtName::XclImpExtName( XclImpSupbook
& rSupbook
, XclImpStream
& rStrm
, XclSupbookType eSubType
, ExcelToSc
* pFormulaConv
)
349 sal_uInt16
nFlags(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
)
361 maName
= XclImpRoot::GetScAddInName( maName
);
363 else if ( (eSubType
== XclSupbookType::Eurotool
) &&
364 maName
.equalsIgnoreAsciiCase( "EUROCONVERT" ) )
365 meType
= xlExtEuroConvert
;
369 maName
= ScfTools::ConvertToScDefinedName( maName
);
374 meType
= ::get_flagvalue( nFlags
, EXC_EXTN_OLE
, xlExtOLE
, xlExtDDE
);
380 if (rStrm
.GetRecLeft() > 1)
381 mxDdeMatrix
.reset(new XclImpCachedMatrix(rStrm
));
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
;
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
);
399 mxArray
= std::move( pArray
);
403 moMOper
.emplace( rSupbook
.GetSharedStringPool(), rStrm
);
410 XclImpExtName::~XclImpExtName()
414 void XclImpExtName::CreateDdeData( ScDocument
& rDoc
, const OUString
& rApplic
, const OUString
& rTopic
) const
416 ScMatrixRef xResults
;
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
427 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
428 pRefMgr
->storeRangeNameTokens(nFileId
, maName
, *mxArray
);
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
438 bool extractSheetAndRange(const OUString
& rName
, OUString
& rSheet
, OUString
& rRange
)
440 sal_Int32 n
= rName
.getLength();
441 const sal_Unicode
* p
= rName
.getStr();
443 bool bInSheet
= true;
444 for (sal_Int32 i
= 0; i
< n
; ++i
, ++p
)
448 // first character must be '!'.
456 // sheet name to range separator.
459 rSheet
= aBuf
.makeStringAndClear();
467 rRange
= aBuf
.makeStringAndClear();
473 bool XclImpExtName::CreateOleData(const ScDocument
& rDoc
, const OUString
& rUrl
,
474 sal_uInt16
& rFileId
, OUString
& rTabName
, ScRange
& rRange
) const
479 OUString aSheet
, aRangeStr
;
480 if (!extractSheetAndRange(maName
, aSheet
, aRangeStr
))
484 ScRefFlags nRes
= aRange
.ParseAny(aRangeStr
, rDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
485 if ((nRes
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
488 if (aRange
.aStart
.Tab() != aRange
.aEnd
.Tab())
489 // We don't support multi-sheet range for this.
492 const ScMatrix
& rCache
= moMOper
->GetCache();
494 rCache
.GetDimensions(nC
, nR
);
496 // cache matrix is empty.
499 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
500 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(rUrl
);
501 ScExternalRefCache::TableTypeRef xTab
= pRefMgr
->getCacheTable(nFileId
, aSheet
, true);
503 // cache table creation failed.
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
);
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);
524 case ScMatValType::Value
:
526 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(aVal
.fVal
));
527 xTab
->setCell(nCol
, nRow
, pToken
, 0, false);
530 case ScMatValType::String
:
532 ScExternalRefCache::TokenRef
pToken(new formula::FormulaStringToken(aVal
.GetString()));
533 xTab
->setCell(nCol
, nRow
, pToken
, 0, false);
548 bool XclImpExtName::HasFormulaTokens() const
550 return bool(mxArray
);
553 // Cached external cells ======================================================
555 XclImpCrn::XclImpCrn( XclImpStream
& rStrm
, const XclAddress
& rXclPos
) :
556 XclImpCachedValue( rStrm
),
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())
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);
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);
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);
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);
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" );
641 OUString
aEncUrl( rStrm
.ReadUniString() );
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
) );
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
) );
672 meType
= XclSupbookType::Special
;
673 // create dummy list entry
674 maSupbTabList
.push_back( std::make_unique
<XclImpSupbookTab
>( maXclUrl
) );
678 void XclImpSupbook::ReadXct( XclImpStream
& rStrm
)
681 mnSBTab
= rStrm
.ReaduInt16();
684 void XclImpSupbook::ReadCrn( XclImpStream
& rStrm
)
686 if (mnSBTab
>= maSupbTabList
.size())
688 XclImpSupbookTab
& rSbTab
= *maSupbTabList
[mnSBTab
];
689 sal_uInt8 nXclColLast
, nXclColFirst
;
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
708 SAL_WARN("sc", "XclImpSupbook::GetExternName - index must be >0");
711 if (meType
== XclSupbookType::Self
|| nXclIndex
> maExtNameList
.size())
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())
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
) :
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
782 XclImpXtiVector
aNewEntries( nXtiCount
);
783 for( auto& rNewEntry
: aNewEntries
)
785 if (!rStrm
.IsValid())
789 maXtiList
.insert( maXtiList
.begin(), aNewEntries
.begin(), aNewEntries
.end() );
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
;
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
);
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() )
879 const XclImpXti
* pXti
= GetXti( nXtiIndex
);
880 if (!pXti
|| pXti
->mnSupbook
>= maSupbookList
.size())
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
) :
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: */