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 .
24 #include <formula/errorcodes.hxx>
25 #include <oox/token/namespaces.hxx>
26 #include <oox/token/relationship.hxx>
27 #include <unotools/collatorwrapper.hxx>
28 #include <svl/numformat.hxx>
29 #include <svl/zforlist.hxx>
30 #include <sal/log.hxx>
31 #include <document.hxx>
32 #include <scextopt.hxx>
33 #include <externalrefmgr.hxx>
34 #include <tokenarray.hxx>
35 #include <xecontent.hxx>
36 #include <xeformula.hxx>
37 #include <xehelper.hxx>
39 #include <xltools.hxx>
43 #include <string_view>
45 using ::std::unique_ptr
;
47 using ::com::sun::star::uno::Any
;
51 // *** Helper classes ***
53 // External names =============================================================
57 /** This is a base class for any external name (i.e. add-in names or DDE links).
58 @descr Derived classes implement creation and export of the external names. */
59 class XclExpExtNameBase
: public XclExpRecord
, protected XclExpRoot
62 /** @param nFlags The flags to export. */
63 explicit XclExpExtNameBase( const XclExpRoot
& rRoot
,
64 const OUString
& rName
, sal_uInt16 nFlags
= 0 );
66 /** Returns the name string of the external name. */
67 const OUString
& GetName() const { return maName
; }
70 /** Writes the start of the record that is equal in all EXTERNNAME records and calls WriteAddData(). */
71 virtual void WriteBody( XclExpStream
& rStrm
) override
;
72 /** Called to write additional data following the common record contents.
73 @descr Derived classes should overwrite this function to write their data. */
74 virtual void WriteAddData( XclExpStream
& rStrm
);
77 OUString maName
; /// Calc name (title) of the external name.
78 XclExpStringRef mxName
; /// Excel name (title) of the external name.
79 sal_uInt16 mnFlags
; /// Flags for record export.
82 /** Represents an EXTERNNAME record for an add-in function name. */
83 class XclExpExtNameAddIn
: public XclExpExtNameBase
86 explicit XclExpExtNameAddIn( const XclExpRoot
& rRoot
, const OUString
& rName
);
89 /** Writes additional record contents. */
90 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
93 /** Represents an EXTERNNAME record for a DDE link. */
94 class XclExpExtNameDde
: public XclExpExtNameBase
97 explicit XclExpExtNameDde( const XclExpRoot
& rRoot
, const OUString
& rName
,
98 sal_uInt16 nFlags
, const ScMatrix
* pResults
= nullptr );
101 /** Writes additional record contents. */
102 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
105 typedef std::shared_ptr
< XclExpCachedMatrix
> XclExpCachedMatRef
;
106 XclExpCachedMatRef mxMatrix
; /// Cached results of the DDE link.
111 class XclExpExtName
: public XclExpExtNameBase
114 explicit XclExpExtName( const XclExpRoot
& rRoot
, const XclExpSupbook
& rSupbook
, const OUString
& rName
,
115 const ScExternalRefCache::TokenArrayRef
& rArray
);
117 virtual void SaveXml(XclExpXmlStream
& rStrm
) override
;
120 /** Writes additional record contents. */
121 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
124 const XclExpSupbook
& mrSupbook
;
125 unique_ptr
<ScTokenArray
> mpArray
;
128 // List of external names =====================================================
130 /** List of all external names of a sheet. */
131 class XclExpExtNameBuffer
: public XclExpRecordBase
, protected XclExpRoot
134 explicit XclExpExtNameBuffer( const XclExpRoot
& rRoot
);
136 /** Inserts an add-in function name
137 @return The 1-based (Excel-like) list index of the name. */
138 sal_uInt16
InsertAddIn( const OUString
& rName
);
139 /** InsertEuroTool */
140 sal_uInt16
InsertEuroTool( const OUString
& rName
);
141 /** Inserts a DDE link.
142 @return The 1-based (Excel-like) list index of the DDE link. */
143 sal_uInt16
InsertDde( std::u16string_view rApplic
, std::u16string_view rTopic
, const OUString
& rItem
);
145 sal_uInt16
InsertExtName( const XclExpSupbook
& rSupbook
, const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
);
147 /** Writes the EXTERNNAME record list. */
148 virtual void Save( XclExpStream
& rStrm
) override
;
150 virtual void SaveXml(XclExpXmlStream
& rStrm
) override
;
153 /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
154 sal_uInt16
GetIndex( std::u16string_view rName
) const;
155 /** Appends the passed newly crested external name.
156 @return The 1-based (Excel-like) list index of the appended name. */
157 sal_uInt16
AppendNew( XclExpExtNameBase
* pExtName
);
159 XclExpRecordList
< XclExpExtNameBase
> maNameList
; /// The list with all EXTERNNAME records.
162 // Cached external cells ======================================================
164 /** Stores the contents of a consecutive row of external cells (record CRN). */
165 class XclExpCrn
: public XclExpRecord
168 explicit XclExpCrn( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
170 /** Returns true, if the passed value could be appended to this record. */
171 bool InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
173 /** Writes the row and child elements. */
174 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
177 virtual void WriteBody( XclExpStream
& rStrm
) override
;
179 static void WriteBool( XclExpStream
& rStrm
, bool bValue
);
180 static void WriteDouble( XclExpStream
& rStrm
, double fValue
);
181 static void WriteString( XclExpStream
& rStrm
, const OUString
& rValue
);
182 static void WriteError( XclExpStream
& rStrm
, sal_uInt8 nErrCode
);
183 static void WriteEmpty( XclExpStream
& rStrm
);
186 typedef ::std::vector
< Any
> CachedValues
;
188 CachedValues maValues
; /// All cached values.
189 SCCOL mnScCol
; /// Column index of the first external cell.
190 SCROW mnScRow
; /// Row index of the external cells.
195 /** Represents the record XCT which is the header record of a CRN record list.
197 class XclExpXct
: public XclExpRecordBase
, protected XclExpRoot
200 explicit XclExpXct( const XclExpRoot
& rRoot
,
201 const OUString
& rTabName
, sal_uInt16 nSBTab
,
202 ScExternalRefCache::TableTypeRef xCacheTable
);
204 /** Returns the external sheet name. */
205 const XclExpString
& GetTabName() const { return maTabName
; }
207 /** Stores all cells in the given range in the CRN list. */
208 void StoreCellRange( const ScRange
& rRange
);
210 void StoreCell_( const ScAddress
& rCell
);
211 void StoreCellRange_( const ScRange
& rRange
);
213 /** Writes the XCT and all CRN records. */
214 virtual void Save( XclExpStream
& rStrm
) override
;
216 /** Writes the sheetDataSet and child elements. */
217 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
220 ScExternalRefCache::TableTypeRef mxCacheTable
;
221 ScMarkData maUsedCells
; /// Contains addresses of all stored cells.
222 ScRange maBoundRange
; /// Bounding box of maUsedCells.
223 XclExpString maTabName
; /// Sheet name of the external sheet.
224 sal_uInt16 mnSBTab
; /// Referred sheet index in SUPBOOK record.
226 /** Build the internal representation of records to be saved as BIFF or OOXML. */
227 bool BuildCrnList( XclExpCrnList
& rCrnRecs
);
230 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
232 /** Base class for records representing external sheets/documents.
234 In BIFF5/BIFF7, this record is the EXTERNSHEET record containing one sheet
235 of the own or an external document. In BIFF8, this record is the SUPBOOK
236 record representing the entire own or external document with all referenced
239 class XclExpExternSheetBase
: public XclExpRecord
, protected XclExpRoot
242 explicit XclExpExternSheetBase( const XclExpRoot
& rRoot
,
243 sal_uInt16 nRecId
, sal_uInt32 nRecSize
= 0 );
246 /** Creates and returns the list of EXTERNNAME records. */
247 XclExpExtNameBuffer
& GetExtNameBuffer();
248 /** Writes the list of EXTERNNAME records. */
249 void WriteExtNameBuffer( XclExpStream
& rStrm
);
250 /** Writes the list of externalName elements. */
251 void WriteExtNameBufferXml( XclExpXmlStream
& rStrm
);
254 typedef std::shared_ptr
< XclExpExtNameBuffer
> XclExpExtNameBfrRef
;
255 XclExpExtNameBfrRef mxExtNameBfr
; /// List of EXTERNNAME records.
258 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
260 /** Represents an EXTERNSHEET record containing the URL and sheet name of a sheet.
261 @descr This class is used up to BIFF7 only, writing a BIFF8 EXTERNSHEET
262 record is implemented directly in the link manager. */
263 class XclExpExternSheet
: public XclExpExternSheetBase
266 /** Creates an EXTERNSHEET record containing a special code (i.e. own document or sheet). */
267 explicit XclExpExternSheet( const XclExpRoot
& rRoot
, sal_Unicode cCode
);
268 /** Creates an EXTERNSHEET record referring to an internal sheet. */
269 explicit XclExpExternSheet( const XclExpRoot
& rRoot
, std::u16string_view rTabName
);
271 /** Finds or inserts an EXTERNNAME record for add-ins.
272 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
273 sal_uInt16
InsertAddIn( const OUString
& rName
);
275 /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
276 virtual void Save( XclExpStream
& rStrm
) override
;
279 /** Initializes the record data with the passed encoded URL. */
280 void Init( std::u16string_view rEncUrl
);
281 /** Writes the contents of the EXTERNSHEET record. */
282 virtual void WriteBody( XclExpStream
& rStrm
) override
;
285 XclExpString maTabName
; /// The name of the sheet.
288 // External documents (SUPBOOK, BIFF8) ========================================
290 /** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
291 class XclExpSupbook
: public XclExpExternSheetBase
294 /** Creates a SUPBOOK record for internal references. */
295 explicit XclExpSupbook( const XclExpRoot
& rRoot
, sal_uInt16 nXclTabCount
);
296 /** Creates a SUPBOOK record for add-in functions. */
297 explicit XclExpSupbook( const XclExpRoot
& rRoot
);
298 /** EUROTOOL SUPBOOK */
299 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
, XclSupbookType
);
300 /** Creates a SUPBOOK record for an external document. */
301 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
);
302 /** Creates a SUPBOOK record for a DDE link. */
303 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rApplic
, const OUString
& rTopic
);
305 /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
306 bool IsUrlLink( std::u16string_view rUrl
) const;
307 /** Returns true, if this SUPBOOK contains the passed DDE link. */
308 bool IsDdeLink( std::u16string_view rApplic
, std::u16string_view rTopic
) const;
309 /** Fills the passed reference log entry with the URL and sheet names. */
310 void FillRefLogEntry( XclExpRefLogEntry
& rRefLogEntry
,
311 sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) const;
313 /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
314 void StoreCellRange( const ScRange
& rRange
, sal_uInt16 nSBTab
);
316 void StoreCell_( sal_uInt16 nSBTab
, const ScAddress
& rCell
);
317 void StoreCellRange_( sal_uInt16 nSBTab
, const ScRange
& rRange
);
319 sal_uInt16
GetTabIndex( const OUString
& rTabName
) const;
320 sal_uInt16
GetTabCount() const;
322 /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
323 sal_uInt16
InsertTabName( const OUString
& rTabName
, ScExternalRefCache::TableTypeRef
const & xCacheTable
);
324 /** Finds or inserts an EXTERNNAME record for add-ins.
325 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
326 sal_uInt16
InsertAddIn( const OUString
& rName
);
327 /** InsertEuroTool */
328 sal_uInt16
InsertEuroTool( const OUString
& rName
);
329 /** Finds or inserts an EXTERNNAME record for DDE links.
330 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
331 sal_uInt16
InsertDde( const OUString
& rItem
);
333 sal_uInt16
InsertExtName( const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
);
335 /** Get the type of record. */
336 XclSupbookType
GetType() const;
338 /** For references to an external document, 1-based OOXML file ID. */
339 sal_uInt16
GetFileId() const;
341 /** For references to an external document. */
342 const OUString
& GetUrl() const;
344 /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
345 virtual void Save( XclExpStream
& rStrm
) override
;
347 /** Writes the externalBook and all child elements. */
348 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
351 /** Returns the sheet name inside of this SUPBOOK. */
352 const XclExpString
* GetTabName( sal_uInt16 nSBTab
) const;
354 /** Writes the SUPBOOK record contents. */
355 virtual void WriteBody( XclExpStream
& rStrm
) override
;
358 typedef XclExpRecordList
< XclExpXct
> XclExpXctList
;
359 typedef XclExpXctList::RecordRefType XclExpXctRef
;
361 XclExpXctList maXctList
; /// List of XCT records (which contain CRN records).
362 OUString maUrl
; /// URL of the external document or application name for DDE.
363 OUString maDdeTopic
; /// Topic of a DDE link.
364 XclExpString maUrlEncoded
; /// Document name encoded for Excel.
365 XclSupbookType meType
; /// Type of this SUPBOOK record.
366 sal_uInt16 mnXclTabCount
; /// Number of internal sheets.
367 sal_uInt16 mnFileId
; /// 1-based external reference file ID for OOXML
370 // All SUPBOOKS in a document =================================================
372 /** This struct contains a sheet index range for 3D references.
373 @descr This reference consists of an index to a SUPBOOK record and indexes
374 to SUPBOOK sheet names. */
377 sal_uInt16 mnSupbook
; /// Index to SUPBOOK record.
378 sal_uInt16 mnFirstSBTab
; /// Index to the first sheet of the range in the SUPBOOK.
379 sal_uInt16 mnLastSBTab
; /// Index to the last sheet of the range in the SUPBOOK.
381 explicit XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
382 explicit XclExpXti( sal_uInt16 nSupbook
, sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) :
383 mnSupbook( nSupbook
), mnFirstSBTab( nFirstSBTab
), mnLastSBTab( nLastSBTab
) {}
385 /** Writes this XTI structure (inside of the EXTERNSHEET record). */
386 void Save( XclExpStream
& rStrm
) const
387 { rStrm
<< mnSupbook
<< mnFirstSBTab
<< mnLastSBTab
; }
390 bool operator==( const XclExpXti
& rLeft
, const XclExpXti
& rRight
)
393 (rLeft
.mnSupbook
== rRight
.mnSupbook
) &&
394 (rLeft
.mnFirstSBTab
== rRight
.mnFirstSBTab
) &&
395 (rLeft
.mnLastSBTab
== rRight
.mnLastSBTab
);
398 /** Contains a list of all SUPBOOK records and index arrays of external sheets. */
399 class XclExpSupbookBuffer
: public XclExpRecordBase
, protected XclExpRoot
402 explicit XclExpSupbookBuffer( const XclExpRoot
& rRoot
);
404 /** Finds SUPBOOK index and SUPBOOK sheet range from given Excel sheet range.
405 @return An XTI structure containing SUPBOOK and sheet indexes. */
406 XclExpXti
GetXti( sal_uInt16 nFirstXclTab
, sal_uInt16 nLastXclTab
,
407 XclExpRefLogEntry
* pRefLogEntry
= nullptr ) const;
409 /** Stores all cells in the given range in a CRN record list. */
410 void StoreCellRange( const ScRange
& rRange
);
412 void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rCell
);
413 void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
);
415 /** Finds or inserts an EXTERNNAME record for an add-in function name.
416 * @return an optional struct, containing [mnSupbook, mnExtName]
417 rnSupbook Returns the index of the SUPBOOK record which contains the DDE link.
418 rnExtName Returns the 1-based EXTERNNAME record index.
420 std::optional
<XclExpSBIndex
> InsertAddIn(const OUString
& rName
);
421 /** InsertEuroTool */
422 std::optional
<XclExpSBIndex
> InsertEuroTool(const OUString
& rName
);
423 /** Finds or inserts an EXTERNNAME record for DDE links.
424 * @return an optional struct, containing [mnSupbook, mnExtName]
425 * rnSupbook Returns the index of the SUPBOOK record which contains the DDE link.
426 rnExtName Returns the 1-based EXTERNNAME record index.
428 std::optional
<XclExpSBIndex
> InsertDde(const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
);
430 std::optional
<XclExpSBIndex
> InsertExtName(const OUString
& rUrl
, const OUString
& rName
,
431 const ScExternalRefCache::TokenArrayRef
& rArray
);
433 XclExpXti
GetXti( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
434 XclExpRefLogEntry
* pRefLogEntry
);
436 /** Writes all SUPBOOK records with their sub records. */
437 virtual void Save( XclExpStream
& rStrm
) override
;
439 /** Writes all externalBook elements with their child elements to OOXML. */
440 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
442 /** Whether we need to write externalReferences or not. */
443 bool HasExternalReferences() const;
446 typedef XclExpRecordList
< XclExpSupbook
> XclExpSupbookList
;
447 typedef XclExpSupbookList::RecordRefType XclExpSupbookRef
;
450 /** Searches for the SUPBOOK record containing the passed document URL.
451 @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
452 @return List index, if the SUPBOOK record exists (out-parameters are valid). */
453 std::optional
<sal_uInt16
> GetSupbookUrl(XclExpSupbookRef
& rxSupbook
,
454 std::u16string_view rUrl
) const;
455 /** Searches for the SUPBOOK record containing the passed DDE link.
456 @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
457 @return List index, if the SUPBOOK record exists (out-parameters are valid). */
458 std::optional
<sal_uInt16
> GetSupbookDde(XclExpSupbookRef
& rxSupbook
,
459 std::u16string_view rApplic
,
460 std::u16string_view rTopic
) const;
462 /** Appends a new SUPBOOK to the list.
463 @return The list index of the SUPBOOK record. */
464 sal_uInt16
Append( XclExpSupbookRef
const & xSupbook
);
467 XclExpSupbookList maSupbookList
; /// List of all SUPBOOK records.
468 std::vector
< XclExpSBIndex
>
469 maSBIndexVec
; /// SUPBOOK and sheet name index for each Excel sheet.
470 sal_uInt16 mnOwnDocSB
; /// Index to SUPBOOK for own document.
471 sal_uInt16 mnAddInSB
; /// Index to add-in SUPBOOK.
476 // Export link manager ========================================================
478 /** Abstract base class for implementation classes of the link manager. */
479 class XclExpLinkManagerImpl
: protected XclExpRoot
482 /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
483 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
484 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
485 SCTAB nFirstScTab
, SCTAB nLastScTab
,
486 XclExpRefLogEntry
* pRefLogEntry
) = 0;
487 /** Derived classes search for a special EXTERNSHEET index for the own document. */
488 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) = 0;
490 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
491 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
492 XclExpRefLogEntry
* pRefLogEntry
) = 0;
494 /** Derived classes store all cells in the given range in a CRN record list. */
495 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) = 0;
497 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) = 0;
498 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) = 0;
500 /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
501 virtual std::optional
<XclExpSBIndex
> InsertAddIn(const OUString
& rName
) = 0;
502 /** InsertEuroTool */
503 virtual std::optional
<XclExpSBIndex
> InsertEuroTool(const OUString
& rName
)
506 /** Derived classes find or insert an EXTERNNAME record for DDE links. */
507 virtual std::optional
<XclExpSBIndex
> InsertDde(const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) = 0;
509 virtual std::optional
<XclExpSBIndex
> InsertExtName(const OUString
& rUrl
, const OUString
& rName
,
510 const ScExternalRefCache::TokenArrayRef
& rArray
)
513 /** Derived classes write the entire link table to the passed stream. */
514 virtual void Save( XclExpStream
& rStrm
) = 0;
516 /** Derived classes write the entire link table to the passed OOXML stream. */
517 virtual void SaveXml( XclExpXmlStream
& rStrm
) = 0;
520 explicit XclExpLinkManagerImpl( const XclExpRoot
& rRoot
);
525 /** Implementation of the link manager for BIFF5/BIFF7. */
526 class XclExpLinkManagerImpl5
: public XclExpLinkManagerImpl
529 explicit XclExpLinkManagerImpl5( const XclExpRoot
& rRoot
);
531 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
532 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
533 SCTAB nFirstScTab
, SCTAB nLastScTab
,
534 XclExpRefLogEntry
* pRefLogEntry
) override
;
535 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) override
;
537 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
538 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
539 XclExpRefLogEntry
* pRefLogEntry
) override
;
541 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) override
;
543 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) override
;
544 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) override
;
546 virtual std::optional
<XclExpSBIndex
> InsertAddIn(const OUString
& rName
) override
;
548 /** InsertEuroTool */
549 virtual std::optional
<XclExpSBIndex
> InsertEuroTool(const OUString
& rName
) override
;
551 virtual std::optional
<XclExpSBIndex
> InsertDde(const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) override
;
553 virtual std::optional
<XclExpSBIndex
> InsertExtName(const OUString
& rUrl
, const OUString
& rName
,
554 const ScExternalRefCache::TokenArrayRef
& rArray
) override
;
556 virtual void Save( XclExpStream
& rStrm
) override
;
558 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
561 typedef XclExpRecordList
< XclExpExternSheet
> XclExpExtSheetList
;
562 typedef XclExpExtSheetList::RecordRefType XclExpExtSheetRef
;
563 typedef ::std::map
< SCTAB
, sal_uInt16
> XclExpIntTabMap
;
564 typedef ::std::map
< sal_Unicode
, sal_uInt16
> XclExpCodeMap
;
567 /** Returns the number of EXTERNSHEET records. */
568 sal_uInt16
GetExtSheetCount() const;
570 /** Appends an internal EXTERNSHEET record and returns the one-based index. */
571 sal_uInt16
AppendInternal( XclExpExtSheetRef
const & xExtSheet
);
572 /** Creates all EXTERNSHEET records for internal sheets on first call. */
573 void CreateInternal();
575 /** Returns the specified internal EXTERNSHEET record. */
576 XclExpExtSheetRef
GetInternal( sal_uInt16 nExtSheet
);
577 /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
578 XclExpExtSheetRef
FindInternal( sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
, SCTAB nScTab
);
579 /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
580 XclExpExtSheetRef
FindInternal( sal_uInt16
& rnExtSheet
, sal_Unicode cCode
);
583 XclExpExtSheetList maExtSheetList
; /// List with EXTERNSHEET records.
584 XclExpIntTabMap maIntTabMap
; /// Maps internal Calc sheets to EXTERNSHEET records.
585 XclExpCodeMap maCodeMap
; /// Maps special external codes to EXTERNSHEET records.
588 /** Implementation of the link manager for BIFF8 and OOXML. */
589 class XclExpLinkManagerImpl8
: public XclExpLinkManagerImpl
592 explicit XclExpLinkManagerImpl8( const XclExpRoot
& rRoot
);
594 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
595 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
596 SCTAB nFirstScTab
, SCTAB nLastScTab
,
597 XclExpRefLogEntry
* pRefLogEntry
) override
;
598 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) override
;
600 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
601 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
602 XclExpRefLogEntry
* pRefLogEntry
) override
;
604 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) override
;
606 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) override
;
607 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) override
;
609 virtual std::optional
<XclExpSBIndex
> InsertAddIn(const OUString
& rName
) override
;
610 /** InsertEuroTool */
611 virtual std::optional
<XclExpSBIndex
> InsertEuroTool(const OUString
& rName
) override
;
613 virtual std::optional
<XclExpSBIndex
> InsertDde(const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) override
;
615 virtual std::optional
<XclExpSBIndex
> InsertExtName(const OUString
& rUrl
, const OUString
& rName
,
616 const ScExternalRefCache::TokenArrayRef
& rArray
) override
;
618 virtual void Save( XclExpStream
& rStrm
) override
;
620 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
623 /** Searches for or inserts a new XTI structure.
624 @return The 0-based list index of the XTI structure. */
625 sal_uInt16
InsertXti( const XclExpXti
& rXti
);
629 XclExpSupbookBuffer maSBBuffer
; /// List of all SUPBOOK records.
630 std::vector
< XclExpXti
> maXtiVec
; /// List of XTI structures for the EXTERNSHEET record.
635 // *** Implementation ***
637 // Excel sheet indexes ========================================================
640 XclExpTabInfo::XclExpTabInfo( const XclExpRoot
& rRoot
) :
647 mnFirstVisXclTab( 0 )
649 ScDocument
& rDoc
= GetDoc();
650 ScExtDocOptions
& rDocOpt
= GetExtDocOptions();
652 mnScCnt
= rDoc
.GetTableCount();
655 SCTAB nFirstVisScTab
= SCTAB_INVALID
; // first visible sheet
656 SCTAB nFirstExpScTab
= SCTAB_INVALID
; // first exported sheet
658 // --- initialize the flags in the index buffer ---
660 maTabInfoVec
.resize( mnScCnt
);
661 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
663 // ignored sheets (skipped by export, with invalid Excel sheet index)
664 if( rDoc
.IsScenario( nScTab
) )
666 SetFlag( nScTab
, ExcTabBufFlags::Ignore
);
669 // external sheets (skipped, but with valid Excel sheet index for ref's)
670 else if( rDoc
.GetLinkMode( nScTab
) == ScLinkMode::VALUE
)
672 SetFlag( nScTab
, ExcTabBufFlags::Extern
);
679 rDoc
.GetName( nScTab
, maTabInfoVec
[ nScTab
].maScName
);
681 // remember first exported sheet
682 if( nFirstExpScTab
== SCTAB_INVALID
)
683 nFirstExpScTab
= nScTab
;
684 // remember first visible exported sheet
685 if( (nFirstVisScTab
== SCTAB_INVALID
) && rDoc
.IsVisible( nScTab
) )
686 nFirstVisScTab
= nScTab
;
688 // sheet visible (only exported sheets)
689 SetFlag( nScTab
, ExcTabBufFlags::Visible
, rDoc
.IsVisible( nScTab
) );
691 // sheet selected (only exported sheets)
692 if( const ScExtTabSettings
* pTabSett
= rDocOpt
.GetTabSettings( nScTab
) )
693 SetFlag( nScTab
, ExcTabBufFlags::Selected
, pTabSett
->mbSelected
);
695 // sheet mirrored (only exported sheets)
696 SetFlag( nScTab
, ExcTabBufFlags::Mirrored
, rDoc
.IsLayoutRTL( nScTab
) );
700 // --- visible/selected sheets ---
702 SCTAB nDisplScTab
= rDocOpt
.GetDocSettings().mnDisplTab
;
704 // missing viewdata at embedded XLSX OLE objects
705 if (nDisplScTab
== -1 )
706 nDisplScTab
= rDoc
.GetVisibleTab();
708 // find first visible exported sheet
709 if( (nFirstVisScTab
== SCTAB_INVALID
) || !IsExportTab( nFirstVisScTab
) )
711 // no exportable visible sheet -> use first exportable sheet
712 nFirstVisScTab
= nFirstExpScTab
;
713 if( (nFirstVisScTab
== SCTAB_INVALID
) || !IsExportTab( nFirstVisScTab
) )
715 // no exportable sheet at all -> use active sheet and export it
716 nFirstVisScTab
= nDisplScTab
;
717 SetFlag( nFirstVisScTab
, ExcTabBufFlags::SkipMask
, false ); // clear skip flags
719 SetFlag( nFirstVisScTab
, ExcTabBufFlags::Visible
); // must be visible, even if originally hidden
722 // find currently displayed sheet
723 if( !IsExportTab( nDisplScTab
) ) // selected sheet not exported (i.e. scenario) -> use first visible
724 nDisplScTab
= nFirstVisScTab
;
725 SetFlag( nDisplScTab
, ExcTabBufFlags::Visible
| ExcTabBufFlags::Selected
);
727 // number of selected sheets
728 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
729 if( IsSelectedTab( nScTab
) )
732 // --- calculate resulting Excel sheet indexes ---
735 mnFirstVisXclTab
= GetXclTab( nFirstVisScTab
);
736 mnDisplXclTab
= GetXclTab( nDisplScTab
);
738 // --- sorted vectors for index lookup ---
743 bool XclExpTabInfo::IsExportTab( SCTAB nScTab
) const
745 /* Check sheet index before to avoid assertion in GetFlag(). */
746 return (nScTab
< mnScCnt
&& nScTab
>= 0) && !GetFlag( nScTab
, ExcTabBufFlags::SkipMask
);
749 bool XclExpTabInfo::IsExternalTab( SCTAB nScTab
) const
751 /* Check sheet index before to avoid assertion (called from formula
752 compiler also for deleted references). */
753 return (nScTab
< mnScCnt
&& nScTab
>= 0) && GetFlag( nScTab
, ExcTabBufFlags::Extern
);
756 bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab
) const
758 return GetFlag( nScTab
, ExcTabBufFlags::Visible
);
761 bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab
) const
763 return GetFlag( nScTab
, ExcTabBufFlags::Selected
);
766 bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab
) const
768 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
769 return GetXclTab( nScTab
) == mnDisplXclTab
;
772 bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab
) const
774 return GetFlag( nScTab
, ExcTabBufFlags::Mirrored
);
777 OUString
XclExpTabInfo::GetScTabName( SCTAB nScTab
) const
779 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
780 return (nScTab
< mnScCnt
&& nScTab
>= 0) ? maTabInfoVec
[ nScTab
].maScName
: OUString();
783 sal_uInt16
XclExpTabInfo::GetXclTab( SCTAB nScTab
) const
785 return (nScTab
< mnScCnt
&& nScTab
>= 0) ? maTabInfoVec
[ nScTab
].mnXclTab
: EXC_TAB_DELETED
;
788 SCTAB
XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab
) const
790 OSL_ENSURE( nSortedScTab
< mnScCnt
&& nSortedScTab
>= 0, "XclExpTabInfo::GetRealScTab - sheet out of range" );
791 return (nSortedScTab
< mnScCnt
&& nSortedScTab
>= 0) ? maFromSortedVec
[ nSortedScTab
] : SCTAB_INVALID
;
794 bool XclExpTabInfo::GetFlag( SCTAB nScTab
, ExcTabBufFlags nFlags
) const
796 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::GetFlag - sheet out of range" );
797 return (nScTab
< mnScCnt
&& nScTab
>= 0) && (maTabInfoVec
[ nScTab
].mnFlags
& nFlags
);
800 void XclExpTabInfo::SetFlag( SCTAB nScTab
, ExcTabBufFlags nFlags
, bool bSet
)
802 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::SetFlag - sheet out of range" );
803 if( nScTab
< mnScCnt
&& nScTab
>= 0 )
806 maTabInfoVec
[ nScTab
].mnFlags
|= nFlags
;
808 maTabInfoVec
[ nScTab
].mnFlags
&= ~nFlags
;
812 void XclExpTabInfo::CalcXclIndexes()
814 sal_uInt16 nXclTab
= 0;
817 // --- pass 1: process regular sheets ---
818 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
820 if( IsExportTab( nScTab
) )
822 maTabInfoVec
[ nScTab
].mnXclTab
= nXclTab
;
826 maTabInfoVec
[ nScTab
].mnXclTab
= EXC_TAB_DELETED
;
830 // --- pass 2: process external sheets (nXclTab continues) ---
831 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
833 if( IsExternalTab( nScTab
) )
835 maTabInfoVec
[ nScTab
].mnXclTab
= nXclTab
;
841 // result: first occur all exported sheets, followed by all external sheets
844 typedef ::std::pair
< OUString
, SCTAB
> XclExpTabName
;
848 struct XclExpTabNameSort
{
849 bool operator ()( const XclExpTabName
& rArg1
, const XclExpTabName
& rArg2
)
851 // compare the sheet names only
852 return ScGlobal::GetCollator().compareString( rArg1
.first
, rArg2
.first
) < 0;
858 void XclExpTabInfo::CalcSortedIndexes()
860 ScDocument
& rDoc
= GetDoc();
861 ::std::vector
< XclExpTabName
> aVec( mnScCnt
);
864 // fill with sheet names
865 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
867 rDoc
.GetName( nScTab
, aVec
[ nScTab
].first
);
868 aVec
[ nScTab
].second
= nScTab
;
870 ::std::sort( aVec
.begin(), aVec
.end(), XclExpTabNameSort() );
872 // fill index vectors from sorted sheet name vector
873 maFromSortedVec
.resize( mnScCnt
);
874 maToSortedVec
.resize( mnScCnt
);
875 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
877 maFromSortedVec
[ nScTab
] = aVec
[ nScTab
].second
;
878 maToSortedVec
[ aVec
[ nScTab
].second
] = nScTab
;
882 // External names =============================================================
884 XclExpExtNameBase::XclExpExtNameBase(
885 const XclExpRoot
& rRoot
, const OUString
& rName
, sal_uInt16 nFlags
) :
886 XclExpRecord( EXC_ID_EXTERNNAME
),
889 mxName( XclExpStringHelper::CreateString( rRoot
, rName
, XclStrFlags::EightBitLength
) ),
892 OSL_ENSURE( maName
.getLength() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
893 SetRecSize( 6 + mxName
->GetSize() );
896 void XclExpExtNameBase::WriteBody( XclExpStream
& rStrm
)
901 WriteAddData( rStrm
);
904 void XclExpExtNameBase::WriteAddData( XclExpStream
& /*rStrm*/ )
908 XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot
& rRoot
, const OUString
& rName
) :
909 XclExpExtNameBase( rRoot
, rName
)
914 void XclExpExtNameAddIn::WriteAddData( XclExpStream
& rStrm
)
916 // write a #REF! error formula
917 rStrm
<< sal_uInt16( 2 ) << EXC_TOKID_ERR
<< EXC_ERR_REF
;
920 XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot
& rRoot
,
921 const OUString
& rName
, sal_uInt16 nFlags
, const ScMatrix
* pResults
) :
922 XclExpExtNameBase( rRoot
, rName
, nFlags
)
926 mxMatrix
= std::make_shared
<XclExpCachedMatrix
>( *pResults
);
927 AddRecSize( mxMatrix
->GetSize() );
931 void XclExpExtNameDde::WriteAddData( XclExpStream
& rStrm
)
934 mxMatrix
->Save( rStrm
);
937 XclExpExtName::XclExpExtName( const XclExpRoot
& rRoot
, const XclExpSupbook
& rSupbook
,
938 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
) :
939 XclExpExtNameBase( rRoot
, rName
),
941 mpArray(rArray
->Clone())
945 void XclExpExtName::WriteAddData( XclExpStream
& rStrm
)
947 // Write only if it only has a single token that is either a cell or cell
948 // range address. Excel just writes '02 00 1C 17' for all the other types
949 // of external names.
951 using namespace ::formula
;
954 if (mpArray
->GetLen() != 1)
957 const formula::FormulaToken
* p
= mpArray
->FirstToken();
958 if (!p
->IsExternalRef())
961 switch (p
->GetType())
963 case svExternalSingleRef
:
965 const ScSingleRefData
& rRef
= *p
->GetSingleRef();
969 bool bColRel
= rRef
.IsColRel();
970 bool bRowRel
= rRef
.IsRowRel();
971 sal_uInt16 nCol
= static_cast<sal_uInt16
>(rRef
.Col());
972 sal_uInt16 nRow
= static_cast<sal_uInt16
>(rRef
.Row());
973 if (bColRel
) nCol
|= 0x4000;
974 if (bRowRel
) nCol
|= 0x8000;
976 OUString aTabName
= p
->GetString().getString();
977 sal_uInt16 nSBTab
= mrSupbook
.GetTabIndex(aTabName
);
980 rStrm
<< static_cast<sal_uInt16
>(9);
981 // operator token (3A for cell reference)
982 rStrm
<< static_cast<sal_uInt8
>(0x3A);
983 // cell address (Excel's address has 2 sheet IDs.)
984 rStrm
<< nSBTab
<< nSBTab
<< nRow
<< nCol
;
987 case svExternalDoubleRef
:
989 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
990 const ScSingleRefData
& r1
= rRef
.Ref1
;
991 const ScSingleRefData
& r2
= rRef
.Ref2
;
992 if (r1
.IsTabRel() || r2
.IsTabRel())
995 sal_uInt16 nTab1
= r1
.Tab();
996 sal_uInt16 nTab2
= r2
.Tab();
997 bool bCol1Rel
= r1
.IsColRel();
998 bool bRow1Rel
= r1
.IsRowRel();
999 bool bCol2Rel
= r2
.IsColRel();
1000 bool bRow2Rel
= r2
.IsRowRel();
1002 sal_uInt16 nCol1
= static_cast<sal_uInt16
>(r1
.Col());
1003 sal_uInt16 nCol2
= static_cast<sal_uInt16
>(r2
.Col());
1004 sal_uInt16 nRow1
= static_cast<sal_uInt16
>(r1
.Row());
1005 sal_uInt16 nRow2
= static_cast<sal_uInt16
>(r2
.Row());
1006 if (bCol1Rel
) nCol1
|= 0x4000;
1007 if (bRow1Rel
) nCol1
|= 0x8000;
1008 if (bCol2Rel
) nCol2
|= 0x4000;
1009 if (bRow2Rel
) nCol2
|= 0x8000;
1011 OUString aTabName
= p
->GetString().getString();
1012 sal_uInt16 nSBTab
= mrSupbook
.GetTabIndex(aTabName
);
1014 // size is always 13 (0x0D)
1015 rStrm
<< static_cast<sal_uInt16
>(13);
1016 // operator token (3B for area reference)
1017 rStrm
<< static_cast<sal_uInt8
>(0x3B);
1018 // range (area) address
1019 sal_uInt16 nSBTab2
= nSBTab
+ nTab2
- nTab1
;
1020 rStrm
<< nSBTab
<< nSBTab2
<< nRow1
<< nRow2
<< nCol1
<< nCol2
;
1029 // special value for #REF! (02 00 1C 17)
1030 rStrm
<< static_cast<sal_uInt16
>(2) << EXC_TOKID_ERR
<< EXC_ERR_REF
;
1033 void XclExpExtName::SaveXml(XclExpXmlStream
& rStrm
)
1035 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.GetCurrentStream();
1037 /* TODO: mpArray contains external references. It doesn't cause any problems, but it's enough
1038 to export it without the external document identifier. */
1039 if (mpArray
->GetLen())
1041 const OUString aFormula
= XclXmlUtils::ToOUString(GetCompileFormulaContext(), ScAddress(0, 0, 0), mpArray
.get());
1042 pExternalLink
->startElement(XML_definedName
,
1043 XML_name
, maName
.toUtf8(),
1044 XML_refersTo
, aFormula
.toUtf8(),
1045 XML_sheetId
, nullptr);
1049 pExternalLink
->startElement(XML_definedName
,
1050 XML_name
, maName
.toUtf8(),
1051 XML_refersTo
, nullptr,
1052 XML_sheetId
, nullptr);
1055 pExternalLink
->endElement(XML_definedName
);
1058 // List of external names =====================================================
1060 XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot
& rRoot
) :
1065 sal_uInt16
XclExpExtNameBuffer::InsertAddIn( const OUString
& rName
)
1067 sal_uInt16 nIndex
= GetIndex( rName
);
1068 return nIndex
? nIndex
: AppendNew( new XclExpExtNameAddIn( GetRoot(), rName
) );
1071 sal_uInt16
XclExpExtNameBuffer::InsertEuroTool( const OUString
& rName
)
1073 sal_uInt16 nIndex
= GetIndex( rName
);
1074 return nIndex
? nIndex
: AppendNew( new XclExpExtNameBase( GetRoot(), rName
) );
1077 sal_uInt16
XclExpExtNameBuffer::InsertDde(
1078 std::u16string_view rApplic
, std::u16string_view rTopic
, const OUString
& rItem
)
1080 sal_uInt16 nIndex
= GetIndex( rItem
);
1084 if( GetDoc().FindDdeLink( rApplic
, rTopic
, rItem
, SC_DDE_IGNOREMODE
, nPos
) )
1086 // create the leading 'StdDocumentName' EXTERNNAME record
1087 if( maNameList
.IsEmpty() )
1088 AppendNew( new XclExpExtNameDde(
1089 GetRoot(), u
"StdDocumentName"_ustr
, EXC_EXTN_EXPDDE_STDDOC
) );
1091 // try to find DDE result array, but create EXTERNNAME record without them too
1092 const ScMatrix
* pScMatrix
= GetDoc().GetDdeLinkResultMatrix( nPos
);
1093 nIndex
= AppendNew( new XclExpExtNameDde( GetRoot(), rItem
, EXC_EXTN_EXPDDE
, pScMatrix
) );
1099 sal_uInt16
XclExpExtNameBuffer::InsertExtName( const XclExpSupbook
& rSupbook
,
1100 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
1102 sal_uInt16 nIndex
= GetIndex( rName
);
1103 return nIndex
? nIndex
: AppendNew( new XclExpExtName( GetRoot(), rSupbook
, rName
, rArray
) );
1106 void XclExpExtNameBuffer::Save( XclExpStream
& rStrm
)
1108 maNameList
.Save( rStrm
);
1111 void XclExpExtNameBuffer::SaveXml(XclExpXmlStream
& rStrm
)
1113 maNameList
.SaveXml(rStrm
);
1116 sal_uInt16
XclExpExtNameBuffer::GetIndex( std::u16string_view rName
) const
1118 for( size_t nPos
= 0, nSize
= maNameList
.GetSize(); nPos
< nSize
; ++nPos
)
1119 if( maNameList
.GetRecord( nPos
)->GetName() == rName
)
1120 return static_cast< sal_uInt16
>( nPos
+ 1 );
1124 sal_uInt16
XclExpExtNameBuffer::AppendNew( XclExpExtNameBase
* pExtName
)
1126 size_t nSize
= maNameList
.GetSize();
1127 if( nSize
< 0x7FFF )
1129 maNameList
.AppendRecord( pExtName
);
1130 return static_cast< sal_uInt16
>( nSize
+ 1 );
1135 // Cached external cells ======================================================
1137 XclExpCrn::XclExpCrn( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
) :
1138 XclExpRecord( EXC_ID_CRN
, 4 ),
1142 maValues
.push_back( rValue
);
1145 bool XclExpCrn::InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
)
1147 if( (nScRow
!= mnScRow
) || (nScCol
!= static_cast< SCCOL
>( mnScCol
+ maValues
.size() )) )
1149 maValues
.push_back( rValue
);
1153 void XclExpCrn::WriteBody( XclExpStream
& rStrm
)
1155 rStrm
<< static_cast< sal_uInt8
>( mnScCol
+ maValues
.size() - 1 )
1156 << static_cast< sal_uInt8
>( mnScCol
)
1157 << static_cast< sal_uInt16
>( mnScRow
);
1158 for( const auto& rValue
: maValues
)
1160 if( rValue
.has
< bool >() )
1161 WriteBool( rStrm
, rValue
.get
< bool >() );
1162 else if( rValue
.has
< double >() )
1163 WriteDouble( rStrm
, rValue
.get
< double >() );
1164 else if( rValue
.has
< OUString
>() )
1165 WriteString( rStrm
, rValue
.get
< OUString
>() );
1167 WriteEmpty( rStrm
);
1171 void XclExpCrn::WriteBool( XclExpStream
& rStrm
, bool bValue
)
1173 rStrm
<< EXC_CACHEDVAL_BOOL
<< sal_uInt8( bValue
? 1 : 0);
1174 rStrm
.WriteZeroBytes( 7 );
1177 void XclExpCrn::WriteDouble( XclExpStream
& rStrm
, double fValue
)
1179 if( !std::isfinite( fValue
) )
1181 FormulaError nScError
= GetDoubleErrorValue(fValue
);
1182 WriteError( rStrm
, XclTools::GetXclErrorCode( nScError
) );
1186 rStrm
<< EXC_CACHEDVAL_DOUBLE
<< fValue
;
1190 void XclExpCrn::WriteString( XclExpStream
& rStrm
, const OUString
& rValue
)
1192 rStrm
<< EXC_CACHEDVAL_STRING
<< XclExpString( rValue
);
1195 void XclExpCrn::WriteError( XclExpStream
& rStrm
, sal_uInt8 nErrCode
)
1197 rStrm
<< EXC_CACHEDVAL_ERROR
<< nErrCode
;
1198 rStrm
.WriteZeroBytes( 7 );
1201 void XclExpCrn::WriteEmpty( XclExpStream
& rStrm
)
1203 rStrm
<< EXC_CACHEDVAL_EMPTY
;
1204 rStrm
.WriteZeroBytes( 8 );
1207 void XclExpCrn::SaveXml( XclExpXmlStream
& rStrm
)
1209 sax_fastparser::FSHelperPtr pFS
= rStrm
.GetCurrentStream();
1211 pFS
->startElement(XML_row
, XML_r
, OString::number(mnScRow
+ 1));
1213 ScAddress
aAdr( mnScCol
, mnScRow
, 0); // Tab number doesn't matter
1214 for( const auto& rValue
: maValues
)
1216 bool bCloseCell
= true;
1217 if( rValue
.has
< double >() )
1219 double fVal
= rValue
.get
< double >();
1220 if (std::isfinite( fVal
))
1223 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), ScRange(aAdr
)));
1224 pFS
->startElement(XML_v
);
1229 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), ScRange(aAdr
)), XML_t
, "e");
1230 pFS
->startElement(XML_v
);
1231 pFS
->write( "#VALUE!" ); // OOXTODO: support other error values
1234 else if( rValue
.has
< OUString
>() )
1236 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), ScRange(aAdr
)), XML_t
, "str");
1237 pFS
->startElement(XML_v
);
1238 pFS
->write( rValue
.get
< OUString
>() );
1240 else if( rValue
.has
< bool >() )
1242 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), ScRange(aAdr
)), XML_t
, "b");
1243 pFS
->startElement(XML_v
);
1244 pFS
->write( rValue
.get
< bool >() ? "1" : "0" );
1246 // OOXTODO: error type cell t='e'
1249 // Empty/blank cell not stored, only aAdr is incremented.
1254 pFS
->endElement(XML_v
);
1255 pFS
->endElement(XML_cell
);
1260 pFS
->endElement( XML_row
);
1263 // Cached cells of a sheet ====================================================
1265 XclExpXct::XclExpXct( const XclExpRoot
& rRoot
, const OUString
& rTabName
,
1266 sal_uInt16 nSBTab
, ScExternalRefCache::TableTypeRef xCacheTable
) :
1267 XclExpRoot( rRoot
),
1268 mxCacheTable(std::move( xCacheTable
)),
1269 maUsedCells( rRoot
.GetDoc().GetSheetLimits() ),
1270 maBoundRange( ScAddress::INITIALIZE_INVALID
),
1271 maTabName( rTabName
),
1276 void XclExpXct::StoreCellRange( const ScRange
& rRange
)
1278 // #i70418# restrict size of external range to prevent memory overflow
1279 if( (rRange
.aEnd
.Col() - rRange
.aStart
.Col()) * (rRange
.aEnd
.Row() - rRange
.aStart
.Row()) > 1024 )
1282 maUsedCells
.SetMultiMarkArea( rRange
);
1283 maBoundRange
.ExtendTo( rRange
);
1286 void XclExpXct::StoreCell_( const ScAddress
& rCell
)
1288 maUsedCells
.SetMultiMarkArea( ScRange( rCell
) );
1289 maBoundRange
.ExtendTo( ScRange( rCell
) );
1292 void XclExpXct::StoreCellRange_( const ScRange
& rRange
)
1294 maUsedCells
.SetMultiMarkArea( rRange
);
1295 maBoundRange
.ExtendTo( rRange
);
1300 class XclExpCrnList
: public XclExpRecordList
< XclExpCrn
>
1303 /** Inserts the passed value into an existing or new CRN record.
1304 @return True = value inserted successfully, false = CRN list is full. */
1305 bool InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
1308 bool XclExpCrnList::InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
)
1310 RecordRefType xLastRec
= GetLastRecord();
1311 if( xLastRec
&& xLastRec
->InsertValue( nScCol
, nScRow
, rValue
) )
1313 if( GetSize() == SAL_MAX_UINT16
)
1315 AppendNewRecord( new XclExpCrn( nScCol
, nScRow
, rValue
) );
1321 bool XclExpXct::BuildCrnList( XclExpCrnList
& rCrnRecs
)
1326 /* Get the range of used rows in the cache table. This may help to
1327 optimize building the CRN record list if the cache table does not
1328 contain all referred cells, e.g. if big empty ranges are used in the
1330 ::std::pair
< SCROW
, SCROW
> aRowRange
= mxCacheTable
->getRowRange();
1331 if( aRowRange
.first
>= aRowRange
.second
)
1334 /* Crop the bounding range of used cells in this table to Excel limits.
1335 Return if there is no external cell inside these limits. */
1336 if( !GetAddressConverter().ValidateRange( maBoundRange
, false ) )
1339 /* Find the resulting row range that needs to be processed. */
1340 SCROW nScRow1
= ::std::max( aRowRange
.first
, maBoundRange
.aStart
.Row() );
1341 SCROW nScRow2
= ::std::min( aRowRange
.second
- 1, maBoundRange
.aEnd
.Row() );
1342 if( nScRow1
> nScRow2
)
1345 /* Build and collect all CRN records before writing the XCT record. This
1346 is needed to determine the total number of CRN records which must be
1347 known when writing the XCT record (possibly encrypted, so seeking the
1348 output stream back after writing the CRN records is not an option). */
1349 SvNumberFormatter
& rFormatter
= GetFormatter();
1351 for( SCROW nScRow
= nScRow1
; bValid
&& (nScRow
<= nScRow2
); ++nScRow
)
1353 ::std::pair
< SCCOL
, SCCOL
> aColRange
= mxCacheTable
->getColRange( nScRow
);
1354 const SCCOL nScEnd
= ::std::min( aColRange
.second
, GetDoc().GetSheetLimits().GetMaxColCount() );
1355 for( SCCOL nScCol
= aColRange
.first
; bValid
&& (nScCol
< nScEnd
); ++nScCol
)
1357 if( maUsedCells
.IsCellMarked( nScCol
, nScRow
, true ) )
1359 sal_uInt32 nScNumFmt
= 0;
1360 ScExternalRefCache::TokenRef xToken
= mxCacheTable
->getCell( nScCol
, nScRow
, &nScNumFmt
);
1361 using namespace ::formula
;
1363 switch( xToken
->GetType() )
1366 bValid
= (rFormatter
.GetType( nScNumFmt
) == SvNumFormatType::LOGICAL
) ?
1367 rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetDouble() != 0 ) ) :
1368 rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetDouble() ) );
1371 // do not save empty strings (empty cells) to cache
1372 if( !xToken
->GetString().isEmpty() )
1373 bValid
= rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetString().getString() ) );
1384 void XclExpXct::Save( XclExpStream
& rStrm
)
1386 XclExpCrnList aCrnRecs
;
1387 if (!BuildCrnList( aCrnRecs
))
1390 // write the XCT record and the list of CRN records
1391 rStrm
.StartRecord( EXC_ID_XCT
, 4 );
1392 rStrm
<< static_cast< sal_uInt16
>( aCrnRecs
.GetSize() ) << mnSBTab
;
1394 aCrnRecs
.Save( rStrm
);
1397 void XclExpXct::SaveXml( XclExpXmlStream
& rStrm
)
1399 XclExpCrnList aCrnRecs
;
1401 sax_fastparser::FSHelperPtr pFS
= rStrm
.GetCurrentStream();
1403 bool bValid
= BuildCrnList( aCrnRecs
);
1404 pFS
->startElement(XML_sheetData
, XML_sheetId
, OString::number(mnSBTab
));
1408 aCrnRecs
.SaveXml( rStrm
);
1410 pFS
->endElement( XML_sheetData
);
1413 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
1415 XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot
& rRoot
, sal_uInt16 nRecId
, sal_uInt32 nRecSize
) :
1416 XclExpRecord( nRecId
, nRecSize
),
1421 XclExpExtNameBuffer
& XclExpExternSheetBase::GetExtNameBuffer()
1424 mxExtNameBfr
= std::make_shared
<XclExpExtNameBuffer
>( GetRoot() );
1425 return *mxExtNameBfr
;
1428 void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream
& rStrm
)
1431 mxExtNameBfr
->Save( rStrm
);
1434 void XclExpExternSheetBase::WriteExtNameBufferXml( XclExpXmlStream
& rStrm
)
1437 mxExtNameBfr
->SaveXml( rStrm
);
1440 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
1442 XclExpExternSheet::XclExpExternSheet( const XclExpRoot
& rRoot
, sal_Unicode cCode
) :
1443 XclExpExternSheetBase( rRoot
, EXC_ID_EXTERNSHEET
)
1445 Init( OUStringChar(cCode
) );
1448 XclExpExternSheet::XclExpExternSheet( const XclExpRoot
& rRoot
, std::u16string_view rTabName
) :
1449 XclExpExternSheetBase( rRoot
, EXC_ID_EXTERNSHEET
)
1451 // reference to own sheet: \03<sheetname>
1452 Init(Concat2View(OUStringChar(EXC_EXTSH_TABNAME
) + rTabName
));
1455 void XclExpExternSheet::Save( XclExpStream
& rStrm
)
1457 // EXTERNSHEET record
1458 XclExpRecord::Save( rStrm
);
1459 // EXTERNNAME records
1460 WriteExtNameBuffer( rStrm
);
1463 void XclExpExternSheet::Init( std::u16string_view rEncUrl
)
1465 OSL_ENSURE_BIFF( GetBiff() <= EXC_BIFF5
);
1466 maTabName
.AssignByte( rEncUrl
, GetTextEncoding(), XclStrFlags::EightBitLength
);
1467 SetRecSize( maTabName
.GetSize() );
1470 sal_uInt16
XclExpExternSheet::InsertAddIn( const OUString
& rName
)
1472 return GetExtNameBuffer().InsertAddIn( rName
);
1475 void XclExpExternSheet::WriteBody( XclExpStream
& rStrm
)
1477 sal_uInt8 nNameSize
= static_cast< sal_uInt8
>( maTabName
.Len() );
1478 // special case: reference to own sheet (starting with '\03') needs wrong string length
1479 if( maTabName
.GetChar( 0 ) == EXC_EXTSH_TABNAME
)
1482 maTabName
.WriteBuffer( rStrm
);
1485 // External document (SUPBOOK, BIFF8) =========================================
1487 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, sal_uInt16 nXclTabCount
) :
1488 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1489 meType( XclSupbookType::Self
),
1490 mnXclTabCount( nXclTabCount
),
1495 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
) :
1496 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1497 meType( XclSupbookType::Addin
),
1503 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
, XclSupbookType
) :
1504 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
),
1506 maUrlEncoded( rUrl
),
1507 meType( XclSupbookType::Eurotool
),
1511 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1514 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
) :
1515 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
),
1517 maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot
, rUrl
) ),
1518 meType( XclSupbookType::Extern
),
1522 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1524 // We need to create all tables up front to ensure the correct table order.
1525 ScExternalRefManager
* pRefMgr
= rRoot
.GetDoc().GetExternalRefManager();
1526 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId( rUrl
);
1527 mnFileId
= nFileId
+ 1;
1528 ScfStringVec aTabNames
;
1529 pRefMgr
->getAllCachedTableNames( nFileId
, aTabNames
);
1530 size_t nTabIndex
= 0;
1531 for( const auto& rTabName
: aTabNames
)
1533 InsertTabName( rTabName
, pRefMgr
->getCacheTable( nFileId
, nTabIndex
) );
1538 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rApplic
, const OUString
& rTopic
) :
1539 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1541 maDdeTopic( rTopic
),
1542 maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic
, rTopic
) ),
1543 meType( XclSupbookType::Special
),
1547 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1550 bool XclExpSupbook::IsUrlLink( std::u16string_view rUrl
) const
1552 return (meType
== XclSupbookType::Extern
|| meType
== XclSupbookType::Eurotool
) && (maUrl
== rUrl
);
1555 bool XclExpSupbook::IsDdeLink( std::u16string_view rApplic
, std::u16string_view rTopic
) const
1557 return (meType
== XclSupbookType::Special
) && (maUrl
== rApplic
) && (maDdeTopic
== rTopic
);
1560 void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry
& rRefLogEntry
,
1561 sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) const
1563 rRefLogEntry
.mpUrl
= maUrlEncoded
.IsEmpty() ? nullptr : &maUrlEncoded
;
1564 rRefLogEntry
.mpFirstTab
= GetTabName( nFirstSBTab
);
1565 rRefLogEntry
.mpLastTab
= GetTabName( nLastSBTab
);
1568 void XclExpSupbook::StoreCellRange( const ScRange
& rRange
, sal_uInt16 nSBTab
)
1570 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1571 pXct
->StoreCellRange( rRange
);
1574 void XclExpSupbook::StoreCell_( sal_uInt16 nSBTab
, const ScAddress
& rCell
)
1576 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1577 pXct
->StoreCell_( rCell
);
1580 void XclExpSupbook::StoreCellRange_( sal_uInt16 nSBTab
, const ScRange
& rRange
)
1582 // multi-table range is not allowed!
1583 if( rRange
.aStart
.Tab() == rRange
.aEnd
.Tab() )
1584 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1585 pXct
->StoreCellRange_( rRange
);
1588 sal_uInt16
XclExpSupbook::GetTabIndex( const OUString
& rTabName
) const
1590 XclExpString
aXclName(rTabName
);
1591 size_t nSize
= maXctList
.GetSize();
1592 for (size_t i
= 0; i
< nSize
; ++i
)
1594 XclExpXctRef aRec
= maXctList
.GetRecord(i
);
1595 if (aXclName
== aRec
->GetTabName())
1596 return ulimit_cast
<sal_uInt16
>(i
);
1601 sal_uInt16
XclExpSupbook::GetTabCount() const
1603 return ulimit_cast
<sal_uInt16
>(maXctList
.GetSize());
1606 sal_uInt16
XclExpSupbook::InsertTabName( const OUString
& rTabName
, ScExternalRefCache::TableTypeRef
const & xCacheTable
)
1608 SAL_WARN_IF( meType
!= XclSupbookType::Extern
, "sc.filter", "Don't insert sheet names here" );
1609 sal_uInt16 nSBTab
= ulimit_cast
< sal_uInt16
>( maXctList
.GetSize() );
1610 XclExpXctRef xXct
= new XclExpXct( GetRoot(), rTabName
, nSBTab
, xCacheTable
);
1611 AddRecSize( xXct
->GetTabName().GetSize() );
1612 maXctList
.AppendRecord( xXct
);
1616 sal_uInt16
XclExpSupbook::InsertAddIn( const OUString
& rName
)
1618 return GetExtNameBuffer().InsertAddIn( rName
);
1621 sal_uInt16
XclExpSupbook::InsertEuroTool( const OUString
& rName
)
1623 return GetExtNameBuffer().InsertEuroTool( rName
);
1626 sal_uInt16
XclExpSupbook::InsertDde( const OUString
& rItem
)
1628 return GetExtNameBuffer().InsertDde( maUrl
, maDdeTopic
, rItem
);
1631 sal_uInt16
XclExpSupbook::InsertExtName( const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
1633 return GetExtNameBuffer().InsertExtName(*this, rName
, rArray
);
1636 XclSupbookType
XclExpSupbook::GetType() const
1641 sal_uInt16
XclExpSupbook::GetFileId() const
1646 const OUString
& XclExpSupbook::GetUrl() const
1651 void XclExpSupbook::Save( XclExpStream
& rStrm
)
1654 XclExpRecord::Save( rStrm
);
1655 // XCT record, CRN records
1656 maXctList
.Save( rStrm
);
1657 // EXTERNNAME records
1658 WriteExtNameBuffer( rStrm
);
1661 void XclExpSupbook::SaveXml( XclExpXmlStream
& rStrm
)
1663 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.GetCurrentStream();
1665 // Add relation for this stream, e.g. xl/externalLinks/_rels/externalLink1.xml.rels
1666 sal_uInt16 nLevel
= 0;
1669 // BuildFileName delete ../ and convert them to nLevel
1670 // but addrelation needs ../ instead of nLevel, so we have to convert it back
1671 OUString sFile
= XclExpHyperlink::BuildFileName(nLevel
, bRel
, maUrl
, GetRoot(), true);
1674 sFile
= "../" + sFile
;
1678 OUString sId
= rStrm
.addRelation( pExternalLink
->getOutputStream(),
1679 oox::getRelationship(Relationship::EXTERNALLINKPATH
), sFile
, true );
1681 pExternalLink
->startElement( XML_externalLink
,
1682 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)).toUtf8());
1684 pExternalLink
->startElement( XML_externalBook
,
1685 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
1686 FSNS(XML_r
, XML_id
), sId
.toUtf8());
1688 if (!maXctList
.IsEmpty())
1690 pExternalLink
->startElement(XML_sheetNames
);
1691 for (size_t nPos
= 0, nSize
= maXctList
.GetSize(); nPos
< nSize
; ++nPos
)
1693 pExternalLink
->singleElement(XML_sheetName
,
1694 XML_val
, XclXmlUtils::ToOString(maXctList
.GetRecord(nPos
)->GetTabName()));
1696 pExternalLink
->endElement( XML_sheetNames
);
1702 pExternalLink
->startElement(XML_definedNames
);
1703 // externalName elements
1704 WriteExtNameBufferXml( rStrm
);
1705 pExternalLink
->endElement(XML_definedNames
);
1708 if (!maXctList
.IsEmpty())
1710 pExternalLink
->startElement(XML_sheetDataSet
);
1712 // sheetData elements
1713 maXctList
.SaveXml( rStrm
);
1715 pExternalLink
->endElement( XML_sheetDataSet
);
1718 pExternalLink
->endElement( XML_externalBook
);
1719 pExternalLink
->endElement( XML_externalLink
);
1722 const XclExpString
* XclExpSupbook::GetTabName( sal_uInt16 nSBTab
) const
1724 XclExpXctRef xXct
= maXctList
.GetRecord( nSBTab
);
1725 return xXct
? &xXct
->GetTabName() : nullptr;
1728 void XclExpSupbook::WriteBody( XclExpStream
& rStrm
)
1732 case XclSupbookType::Self
:
1733 rStrm
<< mnXclTabCount
<< EXC_SUPB_SELF
;
1735 case XclSupbookType::Extern
:
1736 case XclSupbookType::Special
:
1737 case XclSupbookType::Eurotool
:
1739 sal_uInt16 nCount
= ulimit_cast
< sal_uInt16
>( maXctList
.GetSize() );
1740 rStrm
<< nCount
<< maUrlEncoded
;
1742 for( size_t nPos
= 0, nSize
= maXctList
.GetSize(); nPos
< nSize
; ++nPos
)
1743 rStrm
<< maXctList
.GetRecord( nPos
)->GetTabName();
1746 case XclSupbookType::Addin
:
1747 rStrm
<< mnXclTabCount
<< EXC_SUPB_ADDIN
;
1750 SAL_WARN( "sc.filter", "Unhandled SUPBOOK type " << meType
);
1754 // All SUPBOOKS in a document =================================================
1756 XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot
& rRoot
) :
1757 XclExpRoot( rRoot
),
1758 mnOwnDocSB( SAL_MAX_UINT16
),
1759 mnAddInSB( SAL_MAX_UINT16
)
1761 XclExpTabInfo
& rTabInfo
= GetTabInfo();
1762 sal_uInt16 nXclCnt
= rTabInfo
.GetXclTabCount();
1763 sal_uInt16 nCodeCnt
= static_cast< sal_uInt16
>( GetExtDocOptions().GetCodeNameCount() );
1764 size_t nCount
= nXclCnt
+ rTabInfo
.GetXclExtTabCount();
1766 OSL_ENSURE( nCount
> 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
1769 maSBIndexVec
.resize( nCount
);
1771 // self-ref SUPBOOK first of list
1772 XclExpSupbookRef xSupbook
= new XclExpSupbook( GetRoot(), ::std::max( nXclCnt
, nCodeCnt
) );
1773 mnOwnDocSB
= Append( xSupbook
);
1774 for( sal_uInt16 nXclTab
= 0; nXclTab
< nXclCnt
; ++nXclTab
)
1775 maSBIndexVec
[ nXclTab
].Set( mnOwnDocSB
, nXclTab
);
1779 XclExpXti
XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab
, sal_uInt16 nLastXclTab
,
1780 XclExpRefLogEntry
* pRefLogEntry
) const
1783 size_t nSize
= maSBIndexVec
.size();
1784 if( (nFirstXclTab
< nSize
) && (nLastXclTab
< nSize
) )
1786 // index of the SUPBOOK record
1787 aXti
.mnSupbook
= maSBIndexVec
[ nFirstXclTab
].mnSupbook
;
1789 // all sheets in the same supbook?
1790 bool bSameSB
= true;
1791 for( sal_uInt16 nXclTab
= nFirstXclTab
+ 1; bSameSB
&& (nXclTab
<= nLastXclTab
); ++nXclTab
)
1793 bSameSB
= maSBIndexVec
[ nXclTab
].mnSupbook
== aXti
.mnSupbook
;
1795 nLastXclTab
= nXclTab
- 1;
1797 aXti
.mnFirstSBTab
= maSBIndexVec
[ nFirstXclTab
].mnSBTab
;
1798 aXti
.mnLastSBTab
= maSBIndexVec
[ nLastXclTab
].mnSBTab
;
1800 // fill external reference log entry (for change tracking)
1803 pRefLogEntry
->mnFirstXclTab
= nFirstXclTab
;
1804 pRefLogEntry
->mnLastXclTab
= nLastXclTab
;
1805 XclExpSupbookRef xSupbook
= maSupbookList
.GetRecord( aXti
.mnSupbook
);
1807 xSupbook
->FillRefLogEntry( *pRefLogEntry
, aXti
.mnFirstSBTab
, aXti
.mnLastSBTab
);
1812 // special range, i.e. for deleted sheets or add-ins
1813 aXti
.mnSupbook
= mnOwnDocSB
;
1814 aXti
.mnFirstSBTab
= nFirstXclTab
;
1815 aXti
.mnLastSBTab
= nLastXclTab
;
1821 void XclExpSupbookBuffer::StoreCellRange( const ScRange
& rRange
)
1823 sal_uInt16 nXclTab
= GetTabInfo().GetXclTab( rRange
.aStart
.Tab() );
1824 if( nXclTab
< maSBIndexVec
.size() )
1826 const XclExpSBIndex
& rSBIndex
= maSBIndexVec
[ nXclTab
];
1827 XclExpSupbookRef xSupbook
= maSupbookList
.GetRecord( rSBIndex
.mnSupbook
);
1828 OSL_ENSURE( xSupbook
, "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
1830 xSupbook
->StoreCellRange( rRange
, rSBIndex
.mnSBTab
);
1836 class FindSBIndexEntry
1839 explicit FindSBIndexEntry(sal_uInt16 nSupbookId
, sal_uInt16 nTabId
) :
1840 mnSupbookId(nSupbookId
), mnTabId(nTabId
) {}
1842 bool operator()(const XclExpSBIndex
& r
) const
1844 return mnSupbookId
== r
.mnSupbook
&& mnTabId
== r
.mnSBTab
;
1848 sal_uInt16 mnSupbookId
;
1854 void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rCell
)
1856 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
1857 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
1861 XclExpSupbookRef xSupbook
;
1862 auto nSupbookId
= GetSupbookUrl(xSupbook
, *pUrl
);
1865 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
1866 nSupbookId
= Append(xSupbook
);
1869 sal_uInt16 nSheetId
= xSupbook
->GetTabIndex(rTabName
);
1870 if (nSheetId
== EXC_NOTAB
)
1871 // specified table name not found in this SUPBOOK.
1874 FindSBIndexEntry
f(*nSupbookId
, nSheetId
);
1875 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
1877 maSBIndexVec
.emplace_back();
1878 XclExpSBIndex
& r
= maSBIndexVec
.back();
1879 r
.mnSupbook
= *nSupbookId
;
1880 r
.mnSBTab
= nSheetId
;
1883 xSupbook
->StoreCell_(nSheetId
, rCell
);
1886 void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
1888 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
1889 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
1893 XclExpSupbookRef xSupbook
;
1894 auto nSupbookId
= GetSupbookUrl(xSupbook
, *pUrl
);
1897 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
1898 nSupbookId
= Append(xSupbook
);
1901 SCTAB nTabCount
= rRange
.aEnd
.Tab() - rRange
.aStart
.Tab() + 1;
1903 // If this is a multi-table range, get token for each table.
1904 using namespace ::formula
;
1905 SCTAB aMatrixListSize
= 0;
1907 // This is a new'ed instance, so we must manage its life cycle here.
1908 ScExternalRefCache::TokenArrayRef pArray
= pRefMgr
->getDoubleRefTokens(nFileId
, rTabName
, rRange
, nullptr);
1912 FormulaTokenArrayPlainIterator
aIter(*pArray
);
1913 for (FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
1915 if (p
->GetType() == svMatrix
)
1917 else if (p
->GetOpCode() != ocSep
)
1919 // This is supposed to be ocSep!!!
1924 if (aMatrixListSize
!= nTabCount
)
1926 // matrix size mismatch!
1930 sal_uInt16 nFirstSheetId
= xSupbook
->GetTabIndex(rTabName
);
1932 ScRange
aRange(rRange
);
1933 aRange
.aStart
.SetTab(0);
1934 aRange
.aEnd
.SetTab(0);
1935 for (SCTAB nTab
= 0; nTab
< nTabCount
; ++nTab
)
1937 sal_uInt16 nSheetId
= nFirstSheetId
+ static_cast<sal_uInt16
>(nTab
);
1938 FindSBIndexEntry
f(*nSupbookId
, nSheetId
);
1939 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
1941 maSBIndexVec
.emplace_back();
1942 XclExpSBIndex
& r
= maSBIndexVec
.back();
1943 r
.mnSupbook
= *nSupbookId
;
1944 r
.mnSBTab
= nSheetId
;
1947 xSupbook
->StoreCellRange_(nSheetId
, aRange
);
1951 std::optional
<XclExpSBIndex
> XclExpSupbookBuffer::InsertAddIn(const OUString
& rName
)
1953 XclExpSupbookRef xSupbook
;
1954 if( mnAddInSB
== SAL_MAX_UINT16
)
1956 xSupbook
= new XclExpSupbook( GetRoot() );
1957 mnAddInSB
= Append( xSupbook
);
1960 xSupbook
= maSupbookList
.GetRecord( mnAddInSB
);
1961 OSL_ENSURE( xSupbook
, "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
1963 sal_uInt16 nExtName
= xSupbook
->InsertAddIn( rName
);
1966 return XclExpSBIndex( mnAddInSB
, nExtName
);
1971 std::optional
<XclExpSBIndex
> XclExpSupbookBuffer::InsertEuroTool( const OUString
& rName
)
1973 XclExpSupbookRef xSupbook
;
1974 OUString
aUrl( u
"\001\010EUROTOOL.XLA"_ustr
);
1975 auto nSupbookId
= GetSupbookUrl(xSupbook
, aUrl
);
1978 xSupbook
= new XclExpSupbook( GetRoot(), aUrl
, XclSupbookType::Eurotool
);
1979 nSupbookId
= Append( xSupbook
);
1982 auto nExtName
= xSupbook
->InsertEuroTool( rName
);
1985 return XclExpSBIndex( *nSupbookId
, nExtName
);
1990 std::optional
<XclExpSBIndex
> XclExpSupbookBuffer::InsertDde(
1991 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
1993 XclExpSupbookRef xSupbook
;
1994 auto nSupbook
= GetSupbookDde( xSupbook
, rApplic
, rTopic
);
1997 xSupbook
= new XclExpSupbook( GetRoot(), rApplic
, rTopic
);
1998 nSupbook
= Append( xSupbook
);
2000 auto nExtName
= xSupbook
->InsertDde( rItem
);
2003 return XclExpSBIndex(*nSupbook
, nExtName
);
2008 std::optional
<XclExpSBIndex
> XclExpSupbookBuffer::InsertExtName( const OUString
& rUrl
,
2009 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
2011 XclExpSupbookRef xSupbook
;
2012 auto nSupbookId
= GetSupbookUrl(xSupbook
, rUrl
);
2015 xSupbook
= new XclExpSupbook(GetRoot(), rUrl
);
2016 nSupbookId
= Append(xSupbook
);
2019 auto nExtName
= xSupbook
->InsertExtName(rName
, rArray
);
2022 return XclExpSBIndex( *nSupbookId
, nExtName
);
2027 XclExpXti
XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2028 XclExpRefLogEntry
* pRefLogEntry
)
2030 XclExpXti
aXti(0, EXC_NOTAB
, EXC_NOTAB
);
2031 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
2032 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
2036 XclExpSupbookRef xSupbook
;
2037 auto nSupbookId
= GetSupbookUrl(xSupbook
, *pUrl
);
2040 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
2041 nSupbookId
= Append(xSupbook
);
2043 aXti
.mnSupbook
= *nSupbookId
;
2045 sal_uInt16 nFirstSheetId
= xSupbook
->GetTabIndex(rTabName
);
2046 if (nFirstSheetId
== EXC_NOTAB
)
2048 // first sheet not found in SUPBOOK.
2051 sal_uInt16 nSheetCount
= xSupbook
->GetTabCount();
2052 for (sal_uInt16 i
= 0; i
< nXclTabSpan
; ++i
)
2054 sal_uInt16 nSheetId
= nFirstSheetId
+ i
;
2055 if (nSheetId
>= nSheetCount
)
2058 FindSBIndexEntry
f(*nSupbookId
, nSheetId
);
2059 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
2061 maSBIndexVec
.emplace_back();
2062 XclExpSBIndex
& r
= maSBIndexVec
.back();
2063 r
.mnSupbook
= *nSupbookId
;
2064 r
.mnSBTab
= nSheetId
;
2067 aXti
.mnFirstSBTab
= nSheetId
;
2068 if (i
== nXclTabSpan
- 1)
2069 aXti
.mnLastSBTab
= nSheetId
;
2074 pRefLogEntry
->mnFirstXclTab
= 0;
2075 pRefLogEntry
->mnLastXclTab
= 0;
2077 xSupbook
->FillRefLogEntry(*pRefLogEntry
, aXti
.mnFirstSBTab
, aXti
.mnLastSBTab
);
2083 void XclExpSupbookBuffer::Save( XclExpStream
& rStrm
)
2085 maSupbookList
.Save( rStrm
);
2088 void XclExpSupbookBuffer::SaveXml( XclExpXmlStream
& rStrm
)
2090 // Unused external references are not saved, only kept in memory.
2091 // Those that are saved must be indexed from 1, so indexes must be reordered
2092 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
2093 vector
<sal_uInt16
> aExternFileIds
;
2094 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2096 XclExpSupbookRef
xRef(maSupbookList
.GetRecord(nPos
));
2097 // fileIDs are indexed from 1 in xlsx, and from 0 in ScExternalRefManager
2098 // converting between them require a -1 or +1
2099 if (xRef
->GetType() == XclSupbookType::Extern
)
2100 aExternFileIds
.push_back(xRef
->GetFileId() - 1);
2102 if (aExternFileIds
.size() > 0)
2103 pRefMgr
->setSkipUnusedFileIds(aExternFileIds
);
2105 ::std::map
< sal_uInt16
, OUString
> aMap
;
2106 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2108 XclExpSupbookRef
xRef( maSupbookList
.GetRecord( nPos
));
2109 if (xRef
->GetType() != XclSupbookType::Extern
)
2110 continue; // handle only external reference (for now?)
2112 sal_uInt16 nId
= xRef
->GetFileId();
2113 sal_uInt16 nUsedId
= pRefMgr
->convertFileIdToUsedFileId(nId
- 1) + 1;
2114 const OUString
& rUrl
= xRef
->GetUrl();
2115 ::std::pair
< ::std::map
< sal_uInt16
, OUString
>::iterator
, bool > aInsert(
2116 aMap
.insert( ::std::make_pair( nId
, rUrl
)));
2117 if (!aInsert
.second
)
2119 SAL_WARN( "sc.filter", "XclExpSupbookBuffer::SaveXml: file ID already used: " << nId
<<
2120 " wanted for " << rUrl
<< " and is " << (*aInsert
.first
).second
<<
2121 (rUrl
== (*aInsert
.first
).second
? " multiple Supbook not supported" : ""));
2125 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.CreateOutputStream(
2126 XclXmlUtils::GetStreamName( "xl/", "externalLinks/externalLink", nUsedId
),
2127 XclXmlUtils::GetStreamName( nullptr, "externalLinks/externalLink", nUsedId
),
2128 rStrm
.GetCurrentStream()->getOutputStream(),
2129 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
2130 CREATE_OFFICEDOC_RELATION_TYPE("externalLink"),
2133 // externalReference entry in workbook externalReferences
2134 rStrm
.GetCurrentStream()->singleElement( XML_externalReference
,
2135 FSNS(XML_r
, XML_id
), sId
.toUtf8() );
2137 // Each externalBook in a separate stream.
2138 rStrm
.PushStream( pExternalLink
);
2139 xRef
->SaveXml( rStrm
);
2144 bool XclExpSupbookBuffer::HasExternalReferences() const
2146 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2148 if (maSupbookList
.GetRecord( nPos
)->GetType() == XclSupbookType::Extern
)
2154 std::optional
<sal_uInt16
> XclExpSupbookBuffer::GetSupbookUrl(
2155 XclExpSupbookRef
& rxSupbook
, std::u16string_view rUrl
) const
2157 for( size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2159 rxSupbook
= maSupbookList
.GetRecord( nPos
);
2160 if( rxSupbook
->IsUrlLink( rUrl
) )
2162 return ulimit_cast
< sal_uInt16
>( nPos
);
2168 std::optional
<sal_uInt16
> XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef
& rxSupbook
,
2169 std::u16string_view rApplic
, std::u16string_view rTopic
) const
2171 for( size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2173 rxSupbook
= maSupbookList
.GetRecord( nPos
);
2174 if( rxSupbook
->IsDdeLink( rApplic
, rTopic
) )
2176 return ulimit_cast
< sal_uInt16
>( nPos
);
2182 sal_uInt16
XclExpSupbookBuffer::Append( XclExpSupbookRef
const & xSupbook
)
2184 maSupbookList
.AppendRecord( xSupbook
);
2185 return ulimit_cast
< sal_uInt16
>( maSupbookList
.GetSize() - 1 );
2188 // Export link manager ========================================================
2190 XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot
& rRoot
) :
2195 XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot
& rRoot
) :
2196 XclExpLinkManagerImpl( rRoot
)
2200 void XclExpLinkManagerImpl5::FindExtSheet(
2201 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2202 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2204 FindInternal( rnExtSheet
, rnFirstXclTab
, nFirstScTab
);
2205 if( (rnFirstXclTab
== EXC_TAB_DELETED
) || (nFirstScTab
== nLastScTab
) )
2207 rnLastXclTab
= rnFirstXclTab
;
2211 sal_uInt16 nDummyExtSheet
;
2212 FindInternal( nDummyExtSheet
, rnLastXclTab
, nLastScTab
);
2215 OSL_ENSURE( !pRefLogEntry
, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
2218 sal_uInt16
XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode
)
2220 sal_uInt16 nExtSheet
;
2221 FindInternal( nExtSheet
, cCode
);
2225 void XclExpLinkManagerImpl5::FindExtSheet(
2226 sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, sal_uInt16
/*nXclTabSpan*/,
2227 sal_uInt16
& /*rnExtSheet*/, sal_uInt16
& /*rnFirstSBTab*/, sal_uInt16
& /*rnLastSBTab*/,
2228 XclExpRefLogEntry
* /*pRefLogEntry*/ )
2233 void XclExpLinkManagerImpl5::StoreCellRange( const ScSingleRefData
& /*rRef1*/, const ScSingleRefData
& /*rRef2*/, const ScAddress
& /*rPos*/ )
2238 void XclExpLinkManagerImpl5::StoreCell( sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, const ScAddress
& /*rPos*/ )
2243 void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, const ScRange
& /*rRange*/ )
2248 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl5::InsertAddIn( const OUString
& rName
)
2250 sal_uInt16 nExtSheet
, nExtName
;
2251 XclExpExtSheetRef xExtSheet
= FindInternal( nExtSheet
, EXC_EXTSH_ADDIN
);
2254 nExtName
= xExtSheet
->InsertAddIn( rName
);
2257 return XclExpSBIndex( nExtSheet
, nExtName
);
2263 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl5::InsertEuroTool( const OUString
& /*rName*/ )
2268 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl5::InsertDde(
2269 const OUString
& /*rApplic*/, const OUString
& /*rTopic*/, const OUString
& /*rItem*/ )
2275 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl5::InsertExtName( const OUString
& /*rUrl*/,
2276 const OUString
& /*rName*/, const ScExternalRefCache::TokenArrayRef
& /*rArray*/ )
2282 void XclExpLinkManagerImpl5::Save( XclExpStream
& rStrm
)
2284 if( sal_uInt16 nExtSheetCount
= GetExtSheetCount() )
2286 // EXTERNCOUNT record
2287 XclExpUInt16Record( EXC_ID_EXTERNCOUNT
, nExtSheetCount
).Save( rStrm
);
2288 // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
2289 maExtSheetList
.Save( rStrm
);
2293 void XclExpLinkManagerImpl5::SaveXml( XclExpXmlStream
& /*rStrm*/ )
2298 sal_uInt16
XclExpLinkManagerImpl5::GetExtSheetCount() const
2300 return static_cast< sal_uInt16
>( maExtSheetList
.GetSize() );
2303 sal_uInt16
XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef
const & xExtSheet
)
2305 if( GetExtSheetCount() < 0x7FFF )
2307 maExtSheetList
.AppendRecord( xExtSheet
);
2308 // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
2309 return static_cast< sal_uInt16
>( -GetExtSheetCount() );
2314 void XclExpLinkManagerImpl5::CreateInternal()
2316 if( !maIntTabMap
.empty() )
2319 // create EXTERNSHEET records for all internal exported sheets
2320 XclExpTabInfo
& rTabInfo
= GetTabInfo();
2321 for( SCTAB nScTab
= 0, nScCnt
= rTabInfo
.GetScTabCount(); nScTab
< nScCnt
; ++nScTab
)
2323 if( rTabInfo
.IsExportTab( nScTab
) )
2325 XclExpExtSheetRef xRec
;
2326 if( nScTab
== GetCurrScTab() )
2327 xRec
= new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB
);
2329 xRec
= new XclExpExternSheet( GetRoot(), rTabInfo
.GetScTabName( nScTab
) );
2330 maIntTabMap
[ nScTab
] = AppendInternal( xRec
);
2335 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet
)
2337 return maExtSheetList
.GetRecord( static_cast< sal_uInt16
>( -nExtSheet
- 1 ) );
2340 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::FindInternal(
2341 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
, SCTAB nScTab
)
2343 // create internal EXTERNSHEET records on demand
2346 // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
2347 XclExpExtSheetRef xExtSheet
;
2348 XclExpIntTabMap::const_iterator aIt
= maIntTabMap
.find( nScTab
);
2349 if( aIt
== maIntTabMap
.end() )
2351 xExtSheet
= FindInternal( rnExtSheet
, EXC_EXTSH_OWNDOC
);
2352 rnXclTab
= EXC_TAB_DELETED
;
2356 rnExtSheet
= aIt
->second
;
2357 xExtSheet
= GetInternal( rnExtSheet
);
2358 rnXclTab
= GetTabInfo().GetXclTab( nScTab
);
2363 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::FindInternal(
2364 sal_uInt16
& rnExtSheet
, sal_Unicode cCode
)
2366 XclExpExtSheetRef xExtSheet
;
2367 XclExpCodeMap::const_iterator aIt
= maCodeMap
.find( cCode
);
2368 if( aIt
== maCodeMap
.end() )
2370 xExtSheet
= new XclExpExternSheet( GetRoot(), cCode
);
2371 rnExtSheet
= maCodeMap
[ cCode
] = AppendInternal( xExtSheet
);
2375 rnExtSheet
= aIt
->second
;
2376 xExtSheet
= GetInternal( rnExtSheet
);
2381 XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot
& rRoot
) :
2382 XclExpLinkManagerImpl( rRoot
),
2387 void XclExpLinkManagerImpl8::FindExtSheet(
2388 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2389 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2391 XclExpTabInfo
& rTabInfo
= GetTabInfo();
2392 rnFirstXclTab
= rTabInfo
.GetXclTab( nFirstScTab
);
2393 rnLastXclTab
= rTabInfo
.GetXclTab( nLastScTab
);
2394 rnExtSheet
= InsertXti( maSBBuffer
.GetXti( rnFirstXclTab
, rnLastXclTab
, pRefLogEntry
) );
2397 sal_uInt16
XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode
)
2399 OSL_ENSURE( (cCode
== EXC_EXTSH_OWNDOC
) || (cCode
== EXC_EXTSH_ADDIN
),
2400 "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
2401 return InsertXti( maSBBuffer
.GetXti( EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2404 void XclExpLinkManagerImpl8::FindExtSheet(
2405 sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2406 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
2407 XclExpRefLogEntry
* pRefLogEntry
)
2409 XclExpXti aXti
= maSBBuffer
.GetXti(nFileId
, rTabName
, nXclTabSpan
, pRefLogEntry
);
2410 rnExtSheet
= InsertXti(aXti
);
2411 rnFirstSBTab
= aXti
.mnFirstSBTab
;
2412 rnLastSBTab
= aXti
.mnLastSBTab
;
2415 void XclExpLinkManagerImpl8::StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
)
2417 ScAddress aAbs1
= rRef1
.toAbs(GetRoot().GetDoc(), rPos
);
2418 ScAddress aAbs2
= rRef2
.toAbs(GetRoot().GetDoc(), rPos
);
2419 if (!(!rRef1
.IsDeleted() && !rRef2
.IsDeleted() && (aAbs1
.Tab() >= 0) && (aAbs2
.Tab() >= 0)))
2422 const XclExpTabInfo
& rTabInfo
= GetTabInfo();
2423 SCTAB nFirstScTab
= aAbs1
.Tab();
2424 SCTAB nLastScTab
= aAbs2
.Tab();
2425 ScRange
aRange(aAbs1
.Col(), aAbs1
.Row(), 0, aAbs2
.Col(), aAbs2
.Row(), 0);
2426 for (SCTAB nScTab
= nFirstScTab
; nScTab
<= nLastScTab
; ++nScTab
)
2428 if( rTabInfo
.IsExternalTab( nScTab
) )
2430 aRange
.aStart
.SetTab( nScTab
);
2431 aRange
.aEnd
.SetTab( nScTab
);
2432 maSBBuffer
.StoreCellRange( aRange
);
2437 void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
)
2439 maSBBuffer
.StoreCell(nFileId
, rTabName
, rPos
);
2442 void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
2444 maSBBuffer
.StoreCellRange(nFileId
, rTabName
, rRange
);
2447 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl8::InsertAddIn( const OUString
& rName
)
2449 const auto pResult
= maSBBuffer
.InsertAddIn( rName
);
2452 return XclExpSBIndex(InsertXti( XclExpXti( pResult
->mnSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) ), pResult
->mnSBTab
);
2457 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl8::InsertEuroTool( const OUString
& rName
)
2459 const auto pResult
= maSBBuffer
.InsertEuroTool( rName
);
2462 return XclExpSBIndex(InsertXti( XclExpXti( pResult
->mnSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) ),
2468 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl8::InsertDde(
2469 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
2471 const auto pResult
= maSBBuffer
.InsertDde( rApplic
, rTopic
, rItem
);
2474 return XclExpSBIndex(InsertXti( XclExpXti( pResult
->mnSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) ),
2480 std::optional
<XclExpSBIndex
> XclExpLinkManagerImpl8::InsertExtName( const OUString
& rUrl
, const OUString
& rName
,
2481 const ScExternalRefCache::TokenArrayRef
& rArray
)
2483 const auto pResult
= maSBBuffer
.InsertExtName( rUrl
, rName
, rArray
);
2486 return XclExpSBIndex(InsertXti( XclExpXti( pResult
->mnSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) ),
2492 void XclExpLinkManagerImpl8::Save( XclExpStream
& rStrm
)
2494 if( maXtiVec
.empty() )
2497 // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
2498 maSBBuffer
.Save( rStrm
);
2501 sal_uInt16 nCount
= ulimit_cast
< sal_uInt16
>( maXtiVec
.size() );
2502 rStrm
.StartRecord( EXC_ID_EXTERNSHEET
, 2 + 6 * nCount
);
2504 rStrm
.SetSliceSize( 6 );
2505 for( const auto& rXti
: maXtiVec
)
2510 void XclExpLinkManagerImpl8::SaveXml( XclExpXmlStream
& rStrm
)
2512 if (maSBBuffer
.HasExternalReferences())
2514 sax_fastparser::FSHelperPtr pWorkbook
= rStrm
.GetCurrentStream();
2515 pWorkbook
->startElement(XML_externalReferences
);
2517 // externalLink, externalBook, sheetNames, sheetDataSet, externalName
2518 maSBBuffer
.SaveXml( rStrm
);
2520 pWorkbook
->endElement( XML_externalReferences
);
2523 // TODO: equivalent for EXTERNSHEET in OOXML?
2525 if( !maXtiVec
.empty() )
2527 for( const auto& rXti
: maXtiVec
)
2528 rXti
.SaveXml( rStrm
);
2533 sal_uInt16
XclExpLinkManagerImpl8::InsertXti( const XclExpXti
& rXti
)
2535 auto aIt
= std::find(maXtiVec
.begin(), maXtiVec
.end(), rXti
);
2536 if (aIt
!= maXtiVec
.end())
2537 return ulimit_cast
< sal_uInt16
>( std::distance(maXtiVec
.begin(), aIt
) );
2538 maXtiVec
.push_back( rXti
);
2539 return ulimit_cast
< sal_uInt16
>( maXtiVec
.size() - 1 );
2542 XclExpLinkManager::XclExpLinkManager( const XclExpRoot
& rRoot
) :
2548 mxImpl
= std::make_shared
<XclExpLinkManagerImpl5
>( rRoot
);
2551 mxImpl
= std::make_shared
<XclExpLinkManagerImpl8
>( rRoot
);
2558 XclExpLinkManager::~XclExpLinkManager()
2562 void XclExpLinkManager::FindExtSheet(
2563 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
,
2564 SCTAB nScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2566 mxImpl
->FindExtSheet( rnExtSheet
, rnXclTab
, rnXclTab
, nScTab
, nScTab
, pRefLogEntry
);
2569 void XclExpLinkManager::FindExtSheet(
2570 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2571 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2573 mxImpl
->FindExtSheet( rnExtSheet
, rnFirstXclTab
, rnLastXclTab
, nFirstScTab
, nLastScTab
, pRefLogEntry
);
2576 sal_uInt16
XclExpLinkManager::FindExtSheet( sal_Unicode cCode
)
2578 return mxImpl
->FindExtSheet( cCode
);
2581 void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2582 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
2583 XclExpRefLogEntry
* pRefLogEntry
)
2585 mxImpl
->FindExtSheet( nFileId
, rTabName
, nXclTabSpan
, rnExtSheet
, rnFirstSBTab
, rnLastSBTab
, pRefLogEntry
);
2588 void XclExpLinkManager::StoreCell( const ScSingleRefData
& rRef
, const ScAddress
& rPos
)
2590 mxImpl
->StoreCellRange(rRef
, rRef
, rPos
);
2593 void XclExpLinkManager::StoreCellRange( const ScComplexRefData
& rRef
, const ScAddress
& rPos
)
2595 mxImpl
->StoreCellRange(rRef
.Ref1
, rRef
.Ref2
, rPos
);
2598 void XclExpLinkManager::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
)
2600 mxImpl
->StoreCell(nFileId
, rTabName
, rPos
);
2603 void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
2605 mxImpl
->StoreCellRange(nFileId
, rTabName
, rRange
);
2608 std::optional
<XclExpSBIndex
> XclExpLinkManager::InsertAddIn( const OUString
& rName
)
2610 return mxImpl
->InsertAddIn( rName
);
2613 std::optional
<XclExpSBIndex
> XclExpLinkManager::InsertEuroTool( const OUString
& rName
)
2615 return mxImpl
->InsertEuroTool( rName
);
2618 std::optional
<XclExpSBIndex
> XclExpLinkManager::InsertDde(
2619 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
2621 return mxImpl
->InsertDde( rApplic
, rTopic
, rItem
);
2624 std::optional
<XclExpSBIndex
> XclExpLinkManager::InsertExtName( const OUString
& rUrl
, const OUString
& rName
,
2625 const ScExternalRefCache::TokenArrayRef
& rArray
)
2627 return mxImpl
->InsertExtName( rUrl
, rName
, rArray
);
2630 void XclExpLinkManager::Save( XclExpStream
& rStrm
)
2632 mxImpl
->Save( rStrm
);
2635 void XclExpLinkManager::SaveXml( XclExpXmlStream
& rStrm
)
2637 mxImpl
->SaveXml( rStrm
);
2640 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */