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 .
21 #include <document.hxx>
22 #include <scextopt.hxx>
23 #include <xistream.hxx>
24 #include <xihelper.hxx>
26 #include <xltools.hxx>
27 #include <excform.hxx>
28 #include <tokenarray.hxx>
29 #include <externalrefmgr.hxx>
30 #include <scmatrix.hxx>
31 #include <svl/sharedstringpool.hxx>
32 #include <sal/log.hxx>
37 // *** Helper classes ***
39 // Cached external cells ======================================================
44 * Contains the address and value of an external referenced cell.
45 * Note that this is non-copyable, so cannot be used in most stl/boost containers.
47 class XclImpCrn
: public XclImpCachedValue
50 /** Reads a cached value and stores it with its cell address. */
51 explicit XclImpCrn( XclImpStream
& rStrm
, const XclAddress
& rXclPos
);
53 const XclAddress
& GetAddress() const { return maXclPos
;}
56 XclAddress maXclPos
; /// Excel position of the cached cell.
59 // Sheet in an external document ==============================================
61 /** Contains the name and sheet index of one sheet in an external document. */
62 class XclImpSupbookTab
65 /** Stores the sheet name and marks the sheet index as invalid.
66 The sheet index is set while creating the Calc sheet with CreateTable(). */
67 explicit XclImpSupbookTab( const OUString
& rTabName
);
69 const OUString
& GetTabName() const { return maTabName
; }
71 /** Reads a CRN record (external referenced cell) at the specified address. */
72 void ReadCrn( XclImpStream
& rStrm
, const XclAddress
& rXclPos
);
74 void LoadCachedValues( const ScExternalRefCache::TableTypeRef
& pCacheTable
,
75 svl::SharedStringPool
& rPool
);
78 typedef std::shared_ptr
< XclImpCrn
> XclImpCrnRef
;
80 std::vector
< XclImpCrnRef
> maCrnList
; /// List of CRN records (cached cell values).
81 OUString maTabName
; /// Name of the external sheet.
86 // External document (SUPBOOK) ================================================
88 /** This class represents an external linked document (record SUPBOOK).
89 @descr Contains a list of all referenced sheets in the document. */
90 class XclImpSupbook
: protected XclImpRoot
93 /** Reads the SUPBOOK record from stream. */
94 explicit XclImpSupbook( XclImpStream
& rStrm
);
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
);
103 /** Returns the SUPBOOK record type. */
104 XclSupbookType
GetType() const { return meType
; }
106 /** Returns the URL of the external document. */
107 const OUString
& GetXclUrl() const { return maXclUrl
; }
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 OUString
GetMacroName( sal_uInt16 nXclNameIdx
) const;
119 OUString
GetTabName( sal_uInt16 nXtiTab
) const;
121 sal_uInt16
GetTabCount() const;
123 void LoadCachedValues();
125 svl::SharedStringPool
& GetSharedStringPool();
129 std::vector
< std::unique_ptr
<XclImpSupbookTab
> >
130 maSupbTabList
; /// All sheet names of the document.
131 std::vector
< std::unique_ptr
<XclImpExtName
> >
132 maExtNameList
; /// All external names of the document.
133 OUString maXclUrl
; /// URL of the external document (Excel mode).
134 XclSupbookType meType
; /// Type of the supbook record.
135 sal_uInt16 mnSBTab
; /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
138 // Import link manager ========================================================
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. */
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 explicit XclImpXti() : mnSupbook( SAL_MAX_UINT16
), mnSBTabFirst( SAL_MAX_UINT16
), mnSBTabLast( SAL_MAX_UINT16
) {}
153 XclImpStream
& operator>>( XclImpStream
& rStrm
, XclImpXti
& rXti
)
155 rXti
.mnSupbook
= rStrm
.ReaduInt16();
156 rXti
.mnSBTabFirst
= rStrm
.ReaduInt16();
157 rXti
.mnSBTabLast
= rStrm
.ReaduInt16();
163 /** Implementation of the link manager. */
164 class XclImpLinkManagerImpl
: protected XclImpRoot
167 explicit XclImpLinkManagerImpl( const XclImpRoot
& rRoot
);
169 /** Reads the EXTERNSHEET record. */
170 void ReadExternsheet( XclImpStream
& rStrm
);
171 /** Reads a SUPBOOK record. */
172 void ReadSupbook( XclImpStream
& rStrm
);
173 /** Reads an XCT record and appends it to the current SUPBOOK. */
174 void ReadXct( XclImpStream
& rStrm
);
175 /** Reads a CRN record and appends it to the current SUPBOOK. */
176 void ReadCrn( XclImpStream
& rStrm
);
177 /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
178 void ReadExternname( XclImpStream
& rStrm
, ExcelToSc
* pFormulaConv
);
180 /** Returns true, if the specified XTI entry contains an internal reference. */
181 bool IsSelfRef( sal_uInt16 nXtiIndex
) const;
182 /** Returns the Calc sheet index range of the specified XTI entry.
183 @return true = XTI data found, returned sheet index range is valid. */
185 SCTAB
& rnFirstScTab
, SCTAB
& rnLastScTab
,
186 sal_uInt16 nXtiIndex
) const;
187 /** Returns the specified external name or 0 on error. */
188 const XclImpExtName
* GetExternName( sal_uInt16 nXtiIndex
, sal_uInt16 nExtName
) const;
190 /** Returns the absolute file URL of a supporting workbook specified by
192 const OUString
* GetSupbookUrl( sal_uInt16 nXtiIndex
) const;
194 OUString
GetSupbookTabName( sal_uInt16 nXti
, sal_uInt16 nXtiTab
) const;
196 /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
197 @descr For DDE links: Decodes to application name and topic.
198 For OLE object links: Decodes to class name and document URL.
199 @return true = decoding was successful, returned strings are valid (not empty). */
200 bool GetLinkData( OUString
& rApplic
, OUString
& rTopic
, sal_uInt16 nXtiIndex
) const;
201 /** Returns the specified macro name or an empty string on error. */
202 OUString
GetMacroName( sal_uInt16 nExtSheet
, sal_uInt16 nExtName
) const;
205 /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
206 const XclImpXti
* GetXti( sal_uInt16 nXtiIndex
) const;
207 /** Returns the specified SUPBOOK (external document). */
208 const XclImpSupbook
* GetSupbook( sal_uInt16 nXtiIndex
) const;
210 void LoadCachedValues();
213 typedef std::vector
< XclImpXti
> XclImpXtiVector
;
215 XclImpXtiVector maXtiList
; /// List of all XTI structures.
216 std::vector
< std::unique_ptr
<XclImpSupbook
> >
217 maSupbookList
; /// List of external documents.
220 // *** Implementation ***
222 // Excel sheet indexes ========================================================
224 // original Excel sheet names -------------------------------------------------
226 void XclImpTabInfo::AppendXclTabName( const OUString
& rXclTabName
, SCTAB nScTab
)
228 maTabNames
[ rXclTabName
] = nScTab
;
231 void XclImpTabInfo::InsertScTab( SCTAB nScTab
)
233 for( auto& rEntry
: maTabNames
)
234 if( rEntry
.second
>= nScTab
)
238 SCTAB
XclImpTabInfo::GetScTabFromXclName( const OUString
& rXclTabName
) const
240 XclTabNameMap::const_iterator aIt
= maTabNames
.find( rXclTabName
);
241 return (aIt
!= maTabNames
.end()) ? aIt
->second
: SCTAB_INVALID
;
244 // record creation order - TABID record ---------------------------------------
246 void XclImpTabInfo::ReadTabid( XclImpStream
& rStrm
)
248 OSL_ENSURE_BIFF( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
);
249 if( rStrm
.GetRoot().GetBiff() == EXC_BIFF8
)
251 rStrm
.EnableDecryption();
252 std::size_t nReadCount
= rStrm
.GetRecLeft() / 2;
253 OSL_ENSURE( nReadCount
<= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
255 maTabIdVec
.reserve( nReadCount
);
256 for( std::size_t nIndex
= 0; rStrm
.IsValid() && (nIndex
< nReadCount
); ++nIndex
)
257 // zero index is not allowed in BIFF8, but it seems that it occurs in real life
258 maTabIdVec
.push_back( rStrm
.ReaduInt16() );
262 sal_uInt16
XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId
, sal_uInt16 nMaxTabId
) const
264 sal_uInt16 nReturn
= 0;
265 for( sal_uInt16 nValue
: maTabIdVec
)
267 if( nValue
== nCreatedId
)
269 if( nValue
<= nMaxTabId
)
275 // External names =============================================================
277 XclImpExtName::MOper::MOper(svl::SharedStringPool
& rPool
, XclImpStream
& rStrm
) :
278 mxCached(new ScMatrix(0,0))
280 SCSIZE nLastCol
= rStrm
.ReaduInt8();
281 SCSIZE nLastRow
= rStrm
.ReaduInt16();
283 //assuming worst case scenario of nOp + one byte unistring len
284 const size_t nMinRecordSize
= 2;
285 const size_t nMaxRows
= rStrm
.GetRecLeft() / (nMinRecordSize
* (nLastCol
+1));
286 if (nLastRow
>= nMaxRows
)
288 SAL_WARN("sc", "Parsing error: " << nMaxRows
<<
289 " max possible rows, but " << nLastRow
<< " index claimed, truncating");
291 nLastRow
= nMaxRows
-1;
296 mxCached
->Resize(nLastCol
+1, nLastRow
+1);
297 for (SCSIZE nRow
= 0; nRow
<= nLastRow
; ++nRow
)
299 for (SCSIZE nCol
= 0; nCol
<= nLastCol
; ++nCol
)
302 nOp
= rStrm
.ReaduInt8();
307 double fVal
= rStrm
.ReadDouble();
308 mxCached
->PutDouble(fVal
, nCol
, nRow
);
313 OUString aStr
= rStrm
.ReadUniString();
314 mxCached
->PutString(rPool
.intern(aStr
), nCol
, nRow
);
319 bool bVal
= rStrm
.ReaduInt8();
320 mxCached
->PutBoolean(bVal
, nCol
, nRow
);
326 sal_uInt8 nErr
= rStrm
.ReaduInt8();
327 // Map the error code from xls to calc.
328 mxCached
->PutError(XclTools::GetScErrorCode(nErr
), nCol
, nRow
);
339 const ScMatrix
& XclImpExtName::MOper::GetCache() const
344 XclImpExtName::XclImpExtName( XclImpSupbook
& rSupbook
, XclImpStream
& rStrm
, XclSupbookType eSubType
, ExcelToSc
* pFormulaConv
)
347 sal_uInt16
nFlags(0);
350 nFlags
= rStrm
.ReaduInt16();
351 mnStorageId
= rStrm
.ReaduInt32();
352 nLen
= rStrm
.ReaduInt8();
353 maName
= rStrm
.ReadUniString( nLen
);
354 if( ::get_flag( nFlags
, EXC_EXTN_BUILTIN
) || !::get_flag( nFlags
, EXC_EXTN_OLE_OR_DDE
) )
356 if( eSubType
== XclSupbookType::Addin
)
359 maName
= XclImpRoot::GetScAddInName( maName
);
361 else if ( (eSubType
== XclSupbookType::Eurotool
) &&
362 maName
.equalsIgnoreAsciiCase( "EUROCONVERT" ) )
363 meType
= xlExtEuroConvert
;
367 maName
= ScfTools::ConvertToScDefinedName( maName
);
372 meType
= ::get_flagvalue( nFlags
, EXC_EXTN_OLE
, xlExtOLE
, xlExtDDE
);
378 if (rStrm
.GetRecLeft() > 1)
379 mxDdeMatrix
.reset(new XclImpCachedMatrix(rStrm
));
382 // TODO: For now, only global external names are supported. In future
383 // we should extend this to supporting per-sheet external names.
384 if (mnStorageId
== 0 && pFormulaConv
)
386 std::unique_ptr
<ScTokenArray
> pArray
;
388 nFmlaLen
= rStrm
.ReaduInt16();
389 std::vector
<OUString
> aTabNames
;
390 sal_uInt16 nCount
= rSupbook
.GetTabCount();
391 aTabNames
.reserve(nCount
);
392 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
393 aTabNames
.push_back(rSupbook
.GetTabName(i
));
395 pFormulaConv
->ConvertExternName(pArray
, rStrm
, nFmlaLen
, rSupbook
.GetXclUrl(), aTabNames
);
397 mxArray
= std::move( pArray
);
401 mpMOper
.reset( new MOper(rSupbook
.GetSharedStringPool(), rStrm
) );
408 XclImpExtName::~XclImpExtName()
412 void XclImpExtName::CreateDdeData( ScDocument
& rDoc
, const OUString
& rApplic
, const OUString
& rTopic
) const
414 ScMatrixRef xResults
;
416 xResults
= mxDdeMatrix
->CreateScMatrix(rDoc
.GetSharedStringPool());
417 rDoc
.CreateDdeLink( rApplic
, rTopic
, maName
, SC_DDE_DEFAULT
, xResults
);
420 void XclImpExtName::CreateExtNameData( const ScDocument
& rDoc
, sal_uInt16 nFileId
) const
425 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
426 pRefMgr
->storeRangeNameTokens(nFileId
, maName
, *mxArray
);
432 * Decompose the name into sheet name and range name. An OLE link name is
433 * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
436 bool extractSheetAndRange(const OUString
& rName
, OUString
& rSheet
, OUString
& rRange
)
438 sal_Int32 n
= rName
.getLength();
439 const sal_Unicode
* p
= rName
.getStr();
441 bool bInSheet
= true;
442 for (sal_Int32 i
= 0; i
< n
; ++i
, ++p
)
446 // first character must be '!'.
454 // sheet name to range separator.
457 rSheet
= aBuf
.makeStringAndClear();
465 rRange
= aBuf
.makeStringAndClear();
471 bool XclImpExtName::CreateOleData(const ScDocument
& rDoc
, const OUString
& rUrl
,
472 sal_uInt16
& rFileId
, OUString
& rTabName
, ScRange
& rRange
) const
477 OUString aSheet
, aRangeStr
;
478 if (!extractSheetAndRange(maName
, aSheet
, aRangeStr
))
482 ScRefFlags nRes
= aRange
.ParseAny(aRangeStr
, rDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
483 if ((nRes
& ScRefFlags::VALID
) == ScRefFlags::ZERO
)
486 if (aRange
.aStart
.Tab() != aRange
.aEnd
.Tab())
487 // We don't support multi-sheet range for this.
490 const ScMatrix
& rCache
= mpMOper
->GetCache();
492 rCache
.GetDimensions(nC
, nR
);
494 // cache matrix is empty.
497 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
498 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(rUrl
);
499 ScExternalRefCache::TableTypeRef xTab
= pRefMgr
->getCacheTable(nFileId
, aSheet
, true);
501 // cache table creation failed.
504 xTab
->setWholeTableCached();
505 for (SCSIZE i
= 0; i
< nR
; ++i
)
507 for (SCSIZE j
= 0; j
< nC
; ++j
)
509 SCCOL nCol
= aRange
.aStart
.Col() + j
;
510 SCROW nRow
= aRange
.aStart
.Row() + i
;
512 ScMatrixValue aVal
= rCache
.Get(j
, i
);
515 case ScMatValType::Boolean
:
517 bool b
= aVal
.GetBoolean();
518 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(b
? 1.0 : 0.0));
519 xTab
->setCell(nCol
, nRow
, pToken
, 0, false);
522 case ScMatValType::Value
:
524 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(aVal
.fVal
));
525 xTab
->setCell(nCol
, nRow
, pToken
, 0, false);
528 case ScMatValType::String
:
530 ScExternalRefCache::TokenRef
pToken(new formula::FormulaStringToken(aVal
.GetString()));
531 xTab
->setCell(nCol
, nRow
, pToken
, 0, false);
546 bool XclImpExtName::HasFormulaTokens() const
548 return bool(mxArray
);
551 // Cached external cells ======================================================
553 XclImpCrn::XclImpCrn( XclImpStream
& rStrm
, const XclAddress
& rXclPos
) :
554 XclImpCachedValue( rStrm
),
559 // Sheet in an external document ==============================================
561 XclImpSupbookTab::XclImpSupbookTab( const OUString
& rTabName
) :
562 maTabName( rTabName
)
566 void XclImpSupbookTab::ReadCrn( XclImpStream
& rStrm
, const XclAddress
& rXclPos
)
568 XclImpCrnRef crnRef
= std::make_shared
<XclImpCrn
>(rStrm
, rXclPos
);
569 maCrnList
.push_back( crnRef
);
572 void XclImpSupbookTab::LoadCachedValues( const ScExternalRefCache::TableTypeRef
& pCacheTable
,
573 svl::SharedStringPool
& rPool
)
575 if (maCrnList
.empty())
578 for (const auto& rxCrn
: maCrnList
)
580 const XclImpCrn
* const pCrn
= rxCrn
.get();
581 const XclAddress
& rAddr
= pCrn
->GetAddress();
582 switch (pCrn
->GetType())
584 case EXC_CACHEDVAL_BOOL
:
586 bool b
= pCrn
->GetBool();
587 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(b
? 1.0 : 0.0));
588 pCacheTable
->setCell(rAddr
.mnCol
, rAddr
.mnRow
, pToken
, 0, false);
591 case EXC_CACHEDVAL_DOUBLE
:
593 double f
= pCrn
->GetValue();
594 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(f
));
595 pCacheTable
->setCell(rAddr
.mnCol
, rAddr
.mnRow
, pToken
, 0, false);
598 case EXC_CACHEDVAL_ERROR
:
600 double fError
= XclTools::ErrorToDouble( pCrn
->GetXclError() );
601 ScExternalRefCache::TokenRef
pToken(new formula::FormulaDoubleToken(fError
));
602 pCacheTable
->setCell(rAddr
.mnCol
, rAddr
.mnRow
, pToken
, 0, false);
605 case EXC_CACHEDVAL_STRING
:
607 svl::SharedString
aSS( rPool
.intern( pCrn
->GetString()));
608 ScExternalRefCache::TokenRef
pToken(new formula::FormulaStringToken( aSS
));
609 pCacheTable
->setCell(rAddr
.mnCol
, rAddr
.mnRow
, pToken
, 0, false);
618 // External document (SUPBOOK) ================================================
620 XclImpSupbook::XclImpSupbook( XclImpStream
& rStrm
) :
621 XclImpRoot( rStrm
.GetRoot() ),
622 meType( XclSupbookType::Unknown
),
623 mnSBTab( EXC_TAB_DELETED
)
625 sal_uInt16 nSBTabCnt
;
626 nSBTabCnt
= rStrm
.ReaduInt16();
628 if( rStrm
.GetRecLeft() == 2 )
630 switch( rStrm
.ReaduInt16() )
632 case EXC_SUPB_SELF
: meType
= XclSupbookType::Self
; break;
633 case EXC_SUPB_ADDIN
: meType
= XclSupbookType::Addin
; break;
634 default: OSL_FAIL( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
639 OUString
aEncUrl( rStrm
.ReadUniString() );
641 XclImpUrlHelper::DecodeUrl( maXclUrl
, bSelf
, GetRoot(), aEncUrl
);
643 if( maXclUrl
.equalsIgnoreAsciiCase( "\010EUROTOOL.XLA" ) )
645 meType
= XclSupbookType::Eurotool
;
646 maSupbTabList
.push_back( std::make_unique
<XclImpSupbookTab
>( maXclUrl
) );
650 meType
= XclSupbookType::Extern
;
652 //assuming all empty strings with just len header of 0
653 const size_t nMinRecordSize
= sizeof(sal_Int16
);
654 const size_t nMaxRecords
= rStrm
.GetRecLeft() / nMinRecordSize
;
655 if (nSBTabCnt
> nMaxRecords
)
657 SAL_WARN("sc", "Parsing error: " << nMaxRecords
<<
658 " max possible entries, but " << nSBTabCnt
<< " claimed, truncating");
659 nSBTabCnt
= nMaxRecords
;
662 for( sal_uInt16 nSBTab
= 0; nSBTab
< nSBTabCnt
; ++nSBTab
)
664 OUString
aTabName( rStrm
.ReadUniString() );
665 maSupbTabList
.push_back( std::make_unique
<XclImpSupbookTab
>( aTabName
) );
670 meType
= XclSupbookType::Special
;
671 // create dummy list entry
672 maSupbTabList
.push_back( std::make_unique
<XclImpSupbookTab
>( maXclUrl
) );
676 void XclImpSupbook::ReadXct( XclImpStream
& rStrm
)
679 mnSBTab
= rStrm
.ReaduInt16();
682 void XclImpSupbook::ReadCrn( XclImpStream
& rStrm
)
684 if (mnSBTab
>= maSupbTabList
.size())
686 XclImpSupbookTab
& rSbTab
= *maSupbTabList
[mnSBTab
];
687 sal_uInt8 nXclColLast
, nXclColFirst
;
689 nXclColLast
= rStrm
.ReaduInt8();
690 nXclColFirst
= rStrm
.ReaduInt8();
691 nXclRow
= rStrm
.ReaduInt16();
693 for( sal_uInt8 nXclCol
= nXclColFirst
; (nXclCol
<= nXclColLast
) && (rStrm
.GetRecLeft() > 1); ++nXclCol
)
694 rSbTab
.ReadCrn( rStrm
, XclAddress( nXclCol
, nXclRow
) );
697 void XclImpSupbook::ReadExternname( XclImpStream
& rStrm
, ExcelToSc
* pFormulaConv
)
699 maExtNameList
.push_back( std::make_unique
<XclImpExtName
>( *this, rStrm
, meType
, pFormulaConv
) );
702 const XclImpExtName
* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex
) const
706 SAL_WARN("sc", "XclImpSupbook::GetExternName - index must be >0");
709 if (meType
== XclSupbookType::Self
|| nXclIndex
> maExtNameList
.size())
711 return maExtNameList
[nXclIndex
-1].get();
714 bool XclImpSupbook::GetLinkData( OUString
& rApplic
, OUString
& rTopic
) const
716 return (meType
== XclSupbookType::Special
) && XclImpUrlHelper::DecodeLink( rApplic
, rTopic
, maXclUrl
);
719 OUString
XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx
) const
721 OSL_ENSURE( nXclNameIdx
> 0, "XclImpSupbook::GetMacroName - index must be >0" );
722 const XclImpName
* pName
= (meType
== XclSupbookType::Self
) ? GetNameManager().GetName( nXclNameIdx
) : nullptr;
723 return (pName
&& pName
->IsVBName()) ? pName
->GetScName() : OUString();
726 OUString
XclImpSupbook::GetTabName( sal_uInt16 nXtiTab
) const
728 if (nXtiTab
>= maSupbTabList
.size())
730 return maSupbTabList
[nXtiTab
]->GetTabName();
733 sal_uInt16
XclImpSupbook::GetTabCount() const
735 return ulimit_cast
<sal_uInt16
>(maSupbTabList
.size());
738 void XclImpSupbook::LoadCachedValues()
740 if (meType
!= XclSupbookType::Extern
|| GetExtDocOptions().GetDocSettings().mnLinkCnt
> 0 || !GetDocShell())
743 OUString
aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl
, GetDocShell()) );
745 ScExternalRefManager
* pRefMgr
= GetRoot().GetDoc().GetExternalRefManager();
746 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId(aAbsUrl
);
748 for (auto& rxTab
: maSupbTabList
)
750 const OUString
& rTabName
= rxTab
->GetTabName();
751 ScExternalRefCache::TableTypeRef pCacheTable
= pRefMgr
->getCacheTable(nFileId
, rTabName
, true);
752 rxTab
->LoadCachedValues( pCacheTable
, GetSharedStringPool());
753 pCacheTable
->setWholeTableCached();
757 svl::SharedStringPool
& XclImpSupbook::GetSharedStringPool()
759 return GetDoc().GetSharedStringPool();
762 // Import link manager ========================================================
764 XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot
& rRoot
) :
769 void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream
& rStrm
)
771 sal_uInt16 nXtiCount
;
772 nXtiCount
= rStrm
.ReaduInt16();
773 OSL_ENSURE( static_cast< std::size_t >( nXtiCount
* 6 ) == rStrm
.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
774 nXtiCount
= static_cast< sal_uInt16
>( ::std::min
< std::size_t >( nXtiCount
, rStrm
.GetRecLeft() / 6 ) );
776 /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
777 records instead of only one as expected. Surprisingly, Excel seems to
778 insert the entries of the second record before the entries of the first
780 XclImpXtiVector
aNewEntries( nXtiCount
);
781 for( auto& rNewEntry
: aNewEntries
)
783 if (!rStrm
.IsValid())
787 maXtiList
.insert( maXtiList
.begin(), aNewEntries
.begin(), aNewEntries
.end() );
792 void XclImpLinkManagerImpl::ReadSupbook( XclImpStream
& rStrm
)
794 maSupbookList
.push_back( std::make_unique
<XclImpSupbook
>( rStrm
) );
797 void XclImpLinkManagerImpl::ReadXct( XclImpStream
& rStrm
)
799 if( !maSupbookList
.empty() )
800 maSupbookList
.back()->ReadXct( rStrm
);
803 void XclImpLinkManagerImpl::ReadCrn( XclImpStream
& rStrm
)
805 if( !maSupbookList
.empty() )
806 maSupbookList
.back()->ReadCrn( rStrm
);
809 void XclImpLinkManagerImpl::ReadExternname( XclImpStream
& rStrm
, ExcelToSc
* pFormulaConv
)
811 if( !maSupbookList
.empty() )
812 maSupbookList
.back()->ReadExternname( rStrm
, pFormulaConv
);
815 bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex
) const
817 const XclImpSupbook
* pSupbook
= GetSupbook( nXtiIndex
);
818 return pSupbook
&& (pSupbook
->GetType() == XclSupbookType::Self
);
821 bool XclImpLinkManagerImpl::GetScTabRange(
822 SCTAB
& rnFirstScTab
, SCTAB
& rnLastScTab
, sal_uInt16 nXtiIndex
) const
824 if( const XclImpXti
* pXti
= GetXti( nXtiIndex
) )
826 if (!maSupbookList
.empty() && (pXti
->mnSupbook
< maSupbookList
.size()) )
828 rnFirstScTab
= pXti
->mnSBTabFirst
;
829 rnLastScTab
= pXti
->mnSBTabLast
;
836 const XclImpExtName
* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex
, sal_uInt16 nExtName
) const
838 const XclImpSupbook
* pSupbook
= GetSupbook( nXtiIndex
);
839 return pSupbook
? pSupbook
->GetExternName( nExtName
) : nullptr;
842 const OUString
* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex
) const
844 const XclImpSupbook
* p
= GetSupbook( nXtiIndex
);
847 return &p
->GetXclUrl();
850 OUString
XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti
, sal_uInt16 nXtiTab
) const
852 const XclImpSupbook
* p
= GetSupbook(nXti
);
853 return p
? p
->GetTabName(nXtiTab
) : OUString();
856 bool XclImpLinkManagerImpl::GetLinkData( OUString
& rApplic
, OUString
& rTopic
, sal_uInt16 nXtiIndex
) const
858 const XclImpSupbook
* pSupbook
= GetSupbook( nXtiIndex
);
859 return pSupbook
&& pSupbook
->GetLinkData( rApplic
, rTopic
);
862 OUString
XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet
, sal_uInt16 nExtName
) const
864 const XclImpSupbook
* pSupbook
= GetSupbook( nExtSheet
);
865 return pSupbook
? pSupbook
->GetMacroName( nExtName
) : OUString();
868 const XclImpXti
* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex
) const
870 return (nXtiIndex
< maXtiList
.size()) ? &maXtiList
[ nXtiIndex
] : nullptr;
873 const XclImpSupbook
* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex
) const
875 if ( maSupbookList
.empty() )
877 const XclImpXti
* pXti
= GetXti( nXtiIndex
);
878 if (!pXti
|| pXti
->mnSupbook
>= maSupbookList
.size())
880 return maSupbookList
.at( pXti
->mnSupbook
).get();
883 void XclImpLinkManagerImpl::LoadCachedValues()
885 // Read all CRN records which can be accessed via XclImpSupbook, and store
886 // the cached values to the external reference manager.
887 for (auto& rxSupbook
: maSupbookList
)
888 rxSupbook
->LoadCachedValues();
891 XclImpLinkManager::XclImpLinkManager( const XclImpRoot
& rRoot
) :
893 mxImpl( new XclImpLinkManagerImpl( rRoot
) )
897 XclImpLinkManager::~XclImpLinkManager()
901 void XclImpLinkManager::ReadExternsheet( XclImpStream
& rStrm
)
903 mxImpl
->ReadExternsheet( rStrm
);
906 void XclImpLinkManager::ReadSupbook( XclImpStream
& rStrm
)
908 mxImpl
->ReadSupbook( rStrm
);
911 void XclImpLinkManager::ReadXct( XclImpStream
& rStrm
)
913 mxImpl
->ReadXct( rStrm
);
916 void XclImpLinkManager::ReadCrn( XclImpStream
& rStrm
)
918 mxImpl
->ReadCrn( rStrm
);
921 void XclImpLinkManager::ReadExternname( XclImpStream
& rStrm
, ExcelToSc
* pFormulaConv
)
923 mxImpl
->ReadExternname( rStrm
, pFormulaConv
);
926 bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex
) const
928 return mxImpl
->IsSelfRef( nXtiIndex
);
931 bool XclImpLinkManager::GetScTabRange(
932 SCTAB
& rnFirstScTab
, SCTAB
& rnLastScTab
, sal_uInt16 nXtiIndex
) const
934 return mxImpl
->GetScTabRange( rnFirstScTab
, rnLastScTab
, nXtiIndex
);
937 const XclImpExtName
* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex
, sal_uInt16 nExtName
) const
939 return mxImpl
->GetExternName( nXtiIndex
, nExtName
);
942 const OUString
* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex
) const
944 return mxImpl
->GetSupbookUrl(nXtiIndex
);
947 OUString
XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti
, sal_uInt16 nXtiTab
) const
949 return mxImpl
->GetSupbookTabName(nXti
, nXtiTab
);
952 bool XclImpLinkManager::GetLinkData( OUString
& rApplic
, OUString
& rTopic
, sal_uInt16 nXtiIndex
) const
954 return mxImpl
->GetLinkData( rApplic
, rTopic
, nXtiIndex
);
957 OUString
XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet
, sal_uInt16 nExtName
) const
959 return mxImpl
->GetMacroName( nExtSheet
, nExtName
);
962 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */