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 .
23 #include <formula/errorcodes.hxx>
24 #include <oox/token/namespaces.hxx>
25 #include <oox/token/relationship.hxx>
26 #include <unotools/collatorwrapper.hxx>
27 #include <svl/numformat.hxx>
28 #include <svl/zforlist.hxx>
29 #include <sal/log.hxx>
30 #include <document.hxx>
31 #include <scextopt.hxx>
32 #include <externalrefmgr.hxx>
33 #include <tokenarray.hxx>
34 #include <xecontent.hxx>
35 #include <xeformula.hxx>
36 #include <xehelper.hxx>
38 #include <xltools.hxx>
42 #include <string_view>
44 using ::std::unique_ptr
;
46 using ::com::sun::star::uno::Any
;
50 // *** Helper classes ***
52 // External names =============================================================
56 /** This is a base class for any external name (i.e. add-in names or DDE links).
57 @descr Derived classes implement creation and export of the external names. */
58 class XclExpExtNameBase
: public XclExpRecord
, protected XclExpRoot
61 /** @param nFlags The flags to export. */
62 explicit XclExpExtNameBase( const XclExpRoot
& rRoot
,
63 const OUString
& rName
, sal_uInt16 nFlags
= 0 );
65 /** Returns the name string of the external name. */
66 const OUString
& GetName() const { return maName
; }
69 /** Writes the start of the record that is equal in all EXTERNNAME records and calls WriteAddData(). */
70 virtual void WriteBody( XclExpStream
& rStrm
) override
;
71 /** Called to write additional data following the common record contents.
72 @descr Derived classes should overwrite this function to write their data. */
73 virtual void WriteAddData( XclExpStream
& rStrm
);
76 OUString maName
; /// Calc name (title) of the external name.
77 XclExpStringRef mxName
; /// Excel name (title) of the external name.
78 sal_uInt16 mnFlags
; /// Flags for record export.
81 /** Represents an EXTERNNAME record for an add-in function name. */
82 class XclExpExtNameAddIn
: public XclExpExtNameBase
85 explicit XclExpExtNameAddIn( const XclExpRoot
& rRoot
, const OUString
& rName
);
88 /** Writes additional record contents. */
89 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
92 /** Represents an EXTERNNAME record for a DDE link. */
93 class XclExpExtNameDde
: public XclExpExtNameBase
96 explicit XclExpExtNameDde( const XclExpRoot
& rRoot
, const OUString
& rName
,
97 sal_uInt16 nFlags
, const ScMatrix
* pResults
= nullptr );
100 /** Writes additional record contents. */
101 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
104 typedef std::shared_ptr
< XclExpCachedMatrix
> XclExpCachedMatRef
;
105 XclExpCachedMatRef mxMatrix
; /// Cached results of the DDE link.
110 class XclExpExtName
: public XclExpExtNameBase
113 explicit XclExpExtName( const XclExpRoot
& rRoot
, const XclExpSupbook
& rSupbook
, const OUString
& rName
,
114 const ScExternalRefCache::TokenArrayRef
& rArray
);
116 virtual void SaveXml(XclExpXmlStream
& rStrm
) override
;
119 /** Writes additional record contents. */
120 virtual void WriteAddData( XclExpStream
& rStrm
) override
;
123 const XclExpSupbook
& mrSupbook
;
124 unique_ptr
<ScTokenArray
> mpArray
;
127 // List of external names =====================================================
129 /** List of all external names of a sheet. */
130 class XclExpExtNameBuffer
: public XclExpRecordBase
, protected XclExpRoot
133 explicit XclExpExtNameBuffer( const XclExpRoot
& rRoot
);
135 /** Inserts an add-in function name
136 @return The 1-based (Excel-like) list index of the name. */
137 sal_uInt16
InsertAddIn( const OUString
& rName
);
138 /** InsertEuroTool */
139 sal_uInt16
InsertEuroTool( const OUString
& rName
);
140 /** Inserts a DDE link.
141 @return The 1-based (Excel-like) list index of the DDE link. */
142 sal_uInt16
InsertDde( std::u16string_view rApplic
, std::u16string_view rTopic
, const OUString
& rItem
);
144 sal_uInt16
InsertExtName( const XclExpSupbook
& rSupbook
, const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
);
146 /** Writes the EXTERNNAME record list. */
147 virtual void Save( XclExpStream
& rStrm
) override
;
149 virtual void SaveXml(XclExpXmlStream
& rStrm
) override
;
152 /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
153 sal_uInt16
GetIndex( std::u16string_view rName
) const;
154 /** Appends the passed newly crested external name.
155 @return The 1-based (Excel-like) list index of the appended name. */
156 sal_uInt16
AppendNew( XclExpExtNameBase
* pExtName
);
158 XclExpRecordList
< XclExpExtNameBase
> maNameList
; /// The list with all EXTERNNAME records.
161 // Cached external cells ======================================================
163 /** Stores the contents of a consecutive row of external cells (record CRN). */
164 class XclExpCrn
: public XclExpRecord
167 explicit XclExpCrn( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
169 /** Returns true, if the passed value could be appended to this record. */
170 bool InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
172 /** Writes the row and child elements. */
173 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
176 virtual void WriteBody( XclExpStream
& rStrm
) override
;
178 static void WriteBool( XclExpStream
& rStrm
, bool bValue
);
179 static void WriteDouble( XclExpStream
& rStrm
, double fValue
);
180 static void WriteString( XclExpStream
& rStrm
, const OUString
& rValue
);
181 static void WriteError( XclExpStream
& rStrm
, sal_uInt8 nErrCode
);
182 static void WriteEmpty( XclExpStream
& rStrm
);
185 typedef ::std::vector
< Any
> CachedValues
;
187 CachedValues maValues
; /// All cached values.
188 SCCOL mnScCol
; /// Column index of the first external cell.
189 SCROW mnScRow
; /// Row index of the external cells.
194 /** Represents the record XCT which is the header record of a CRN record list.
196 class XclExpXct
: public XclExpRecordBase
, protected XclExpRoot
199 explicit XclExpXct( const XclExpRoot
& rRoot
,
200 const OUString
& rTabName
, sal_uInt16 nSBTab
,
201 ScExternalRefCache::TableTypeRef
const & xCacheTable
);
203 /** Returns the external sheet name. */
204 const XclExpString
& GetTabName() const { return maTabName
; }
206 /** Stores all cells in the given range in the CRN list. */
207 void StoreCellRange( const ScRange
& rRange
);
209 void StoreCell_( const ScAddress
& rCell
);
210 void StoreCellRange_( const ScRange
& rRange
);
212 /** Writes the XCT and all CRN records. */
213 virtual void Save( XclExpStream
& rStrm
) override
;
215 /** Writes the sheetDataSet and child elements. */
216 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
219 ScExternalRefCache::TableTypeRef mxCacheTable
;
220 ScMarkData maUsedCells
; /// Contains addresses of all stored cells.
221 ScRange maBoundRange
; /// Bounding box of maUsedCells.
222 XclExpString maTabName
; /// Sheet name of the external sheet.
223 sal_uInt16 mnSBTab
; /// Referred sheet index in SUPBOOK record.
225 /** Build the internal representation of records to be saved as BIFF or OOXML. */
226 bool BuildCrnList( XclExpCrnList
& rCrnRecs
);
229 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
231 /** Base class for records representing external sheets/documents.
233 In BIFF5/BIFF7, this record is the EXTERNSHEET record containing one sheet
234 of the own or an external document. In BIFF8, this record is the SUPBOOK
235 record representing the entire own or external document with all referenced
238 class XclExpExternSheetBase
: public XclExpRecord
, protected XclExpRoot
241 explicit XclExpExternSheetBase( const XclExpRoot
& rRoot
,
242 sal_uInt16 nRecId
, sal_uInt32 nRecSize
= 0 );
245 /** Creates and returns the list of EXTERNNAME records. */
246 XclExpExtNameBuffer
& GetExtNameBuffer();
247 /** Writes the list of EXTERNNAME records. */
248 void WriteExtNameBuffer( XclExpStream
& rStrm
);
249 /** Writes the list of externalName elements. */
250 void WriteExtNameBufferXml( XclExpXmlStream
& rStrm
);
253 typedef std::shared_ptr
< XclExpExtNameBuffer
> XclExpExtNameBfrRef
;
254 XclExpExtNameBfrRef mxExtNameBfr
; /// List of EXTERNNAME records.
257 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
259 /** Represents an EXTERNSHEET record containing the URL and sheet name of a sheet.
260 @descr This class is used up to BIFF7 only, writing a BIFF8 EXTERNSHEET
261 record is implemented directly in the link manager. */
262 class XclExpExternSheet
: public XclExpExternSheetBase
265 /** Creates an EXTERNSHEET record containing a special code (i.e. own document or sheet). */
266 explicit XclExpExternSheet( const XclExpRoot
& rRoot
, sal_Unicode cCode
);
267 /** Creates an EXTERNSHEET record referring to an internal sheet. */
268 explicit XclExpExternSheet( const XclExpRoot
& rRoot
, std::u16string_view rTabName
);
270 /** Finds or inserts an EXTERNNAME record for add-ins.
271 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
272 sal_uInt16
InsertAddIn( const OUString
& rName
);
274 /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
275 virtual void Save( XclExpStream
& rStrm
) override
;
278 /** Initializes the record data with the passed encoded URL. */
279 void Init( std::u16string_view rEncUrl
);
280 /** Writes the contents of the EXTERNSHEET record. */
281 virtual void WriteBody( XclExpStream
& rStrm
) override
;
284 XclExpString maTabName
; /// The name of the sheet.
287 // External documents (SUPBOOK, BIFF8) ========================================
289 /** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
290 class XclExpSupbook
: public XclExpExternSheetBase
293 /** Creates a SUPBOOK record for internal references. */
294 explicit XclExpSupbook( const XclExpRoot
& rRoot
, sal_uInt16 nXclTabCount
);
295 /** Creates a SUPBOOK record for add-in functions. */
296 explicit XclExpSupbook( const XclExpRoot
& rRoot
);
297 /** EUROTOOL SUPBOOK */
298 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
, XclSupbookType
);
299 /** Creates a SUPBOOK record for an external document. */
300 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
);
301 /** Creates a SUPBOOK record for a DDE link. */
302 explicit XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rApplic
, const OUString
& rTopic
);
304 /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
305 bool IsUrlLink( std::u16string_view rUrl
) const;
306 /** Returns true, if this SUPBOOK contains the passed DDE link. */
307 bool IsDdeLink( std::u16string_view rApplic
, std::u16string_view rTopic
) const;
308 /** Fills the passed reference log entry with the URL and sheet names. */
309 void FillRefLogEntry( XclExpRefLogEntry
& rRefLogEntry
,
310 sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) const;
312 /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
313 void StoreCellRange( const ScRange
& rRange
, sal_uInt16 nSBTab
);
315 void StoreCell_( sal_uInt16 nSBTab
, const ScAddress
& rCell
);
316 void StoreCellRange_( sal_uInt16 nSBTab
, const ScRange
& rRange
);
318 sal_uInt16
GetTabIndex( const OUString
& rTabName
) const;
319 sal_uInt16
GetTabCount() const;
321 /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
322 sal_uInt16
InsertTabName( const OUString
& rTabName
, ScExternalRefCache::TableTypeRef
const & xCacheTable
);
323 /** Finds or inserts an EXTERNNAME record for add-ins.
324 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
325 sal_uInt16
InsertAddIn( const OUString
& rName
);
326 /** InsertEuroTool */
327 sal_uInt16
InsertEuroTool( const OUString
& rName
);
328 /** Finds or inserts an EXTERNNAME record for DDE links.
329 @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
330 sal_uInt16
InsertDde( const OUString
& rItem
);
332 sal_uInt16
InsertExtName( const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
);
334 /** Get the type of record. */
335 XclSupbookType
GetType() const;
337 /** For references to an external document, 1-based OOXML file ID. */
338 sal_uInt16
GetFileId() const;
340 /** For references to an external document. */
341 const OUString
& GetUrl() const;
343 /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
344 virtual void Save( XclExpStream
& rStrm
) override
;
346 /** Writes the externalBook and all child elements. */
347 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
350 /** Returns the sheet name inside of this SUPBOOK. */
351 const XclExpString
* GetTabName( sal_uInt16 nSBTab
) const;
353 /** Writes the SUPBOOK record contents. */
354 virtual void WriteBody( XclExpStream
& rStrm
) override
;
357 typedef XclExpRecordList
< XclExpXct
> XclExpXctList
;
358 typedef XclExpXctList::RecordRefType XclExpXctRef
;
360 XclExpXctList maXctList
; /// List of XCT records (which contain CRN records).
361 OUString maUrl
; /// URL of the external document or application name for DDE.
362 OUString maDdeTopic
; /// Topic of a DDE link.
363 XclExpString maUrlEncoded
; /// Document name encoded for Excel.
364 XclSupbookType meType
; /// Type of this SUPBOOK record.
365 sal_uInt16 mnXclTabCount
; /// Number of internal sheets.
366 sal_uInt16 mnFileId
; /// 1-based external reference file ID for OOXML
369 // All SUPBOOKS in a document =================================================
371 /** This struct contains a sheet index range for 3D references.
372 @descr This reference consists of an index to a SUPBOOK record and indexes
373 to SUPBOOK sheet names. */
376 sal_uInt16 mnSupbook
; /// Index to SUPBOOK record.
377 sal_uInt16 mnFirstSBTab
; /// Index to the first sheet of the range in the SUPBOOK.
378 sal_uInt16 mnLastSBTab
; /// Index to the last sheet of the range in the SUPBOOK.
380 explicit XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
381 explicit XclExpXti( sal_uInt16 nSupbook
, sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) :
382 mnSupbook( nSupbook
), mnFirstSBTab( nFirstSBTab
), mnLastSBTab( nLastSBTab
) {}
384 /** Writes this XTI structure (inside of the EXTERNSHEET record). */
385 void Save( XclExpStream
& rStrm
) const
386 { rStrm
<< mnSupbook
<< mnFirstSBTab
<< mnLastSBTab
; }
389 bool operator==( const XclExpXti
& rLeft
, const XclExpXti
& rRight
)
392 (rLeft
.mnSupbook
== rRight
.mnSupbook
) &&
393 (rLeft
.mnFirstSBTab
== rRight
.mnFirstSBTab
) &&
394 (rLeft
.mnLastSBTab
== rRight
.mnLastSBTab
);
397 /** Contains a list of all SUPBOOK records and index arrays of external sheets. */
398 class XclExpSupbookBuffer
: public XclExpRecordBase
, protected XclExpRoot
401 explicit XclExpSupbookBuffer( const XclExpRoot
& rRoot
);
403 /** Finds SUPBOOK index and SUPBOOK sheet range from given Excel sheet range.
404 @return An XTI structure containing SUPBOOK and sheet indexes. */
405 XclExpXti
GetXti( sal_uInt16 nFirstXclTab
, sal_uInt16 nLastXclTab
,
406 XclExpRefLogEntry
* pRefLogEntry
= nullptr ) const;
408 /** Stores all cells in the given range in a CRN record list. */
409 void StoreCellRange( const ScRange
& rRange
);
411 void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rCell
);
412 void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
);
414 /** Finds or inserts an EXTERNNAME record for an add-in function name.
415 @param rnSupbook Returns the index of the SUPBOOK record which contains the add-in function name.
416 @param rnExtName Returns the 1-based EXTERNNAME record index. */
418 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
,
419 const OUString
& rName
);
420 /** InsertEuroTool */
422 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
,
423 const OUString
& rName
);
424 /** Finds or inserts an EXTERNNAME record for DDE links.
425 @param rnSupbook Returns the index of the SUPBOOK record which contains the DDE link.
426 @param rnExtName Returns the 1-based EXTERNNAME record index. */
428 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
,
429 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
);
432 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
, const OUString
& rUrl
,
433 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
);
435 XclExpXti
GetXti( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
436 XclExpRefLogEntry
* pRefLogEntry
);
438 /** Writes all SUPBOOK records with their sub records. */
439 virtual void Save( XclExpStream
& rStrm
) override
;
441 /** Writes all externalBook elements with their child elements to OOXML. */
442 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
444 /** Whether we need to write externalReferences or not. */
445 bool HasExternalReferences() const;
449 sal_uInt16 mnSupbook
; /// SUPBOOK index for an Excel sheet.
450 sal_uInt16 mnSBTab
; /// Sheet name index in SUPBOOK for an Excel sheet.
451 void Set( sal_uInt16 nSupbook
, sal_uInt16 nSBTab
)
452 { mnSupbook
= nSupbook
; mnSBTab
= nSBTab
; }
456 typedef XclExpRecordList
< XclExpSupbook
> XclExpSupbookList
;
457 typedef XclExpSupbookList::RecordRefType XclExpSupbookRef
;
460 /** Searches for the SUPBOOK record containing the passed document URL.
461 @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
462 @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
463 @return True, if the SUPBOOK record exists (out-parameters are valid). */
464 bool GetSupbookUrl( XclExpSupbookRef
& rxSupbook
, sal_uInt16
& rnIndex
,
465 std::u16string_view rUrl
) const;
466 /** Searches for the SUPBOOK record containing the passed DDE link.
467 @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
468 @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
469 @return True, if the SUPBOOK record exists (out-parameters are valid). */
470 bool GetSupbookDde( XclExpSupbookRef
& rxSupbook
, sal_uInt16
& rnIndex
,
471 std::u16string_view rApplic
, std::u16string_view rTopic
) const;
473 /** Appends a new SUPBOOK to the list.
474 @return The list index of the SUPBOOK record. */
475 sal_uInt16
Append( XclExpSupbookRef
const & xSupbook
);
478 XclExpSupbookList maSupbookList
; /// List of all SUPBOOK records.
479 std::vector
< XclExpSBIndex
>
480 maSBIndexVec
; /// SUPBOOK and sheet name index for each Excel sheet.
481 sal_uInt16 mnOwnDocSB
; /// Index to SUPBOOK for own document.
482 sal_uInt16 mnAddInSB
; /// Index to add-in SUPBOOK.
487 // Export link manager ========================================================
489 /** Abstract base class for implementation classes of the link manager. */
490 class XclExpLinkManagerImpl
: protected XclExpRoot
493 /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
494 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
495 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
496 SCTAB nFirstScTab
, SCTAB nLastScTab
,
497 XclExpRefLogEntry
* pRefLogEntry
) = 0;
498 /** Derived classes search for a special EXTERNSHEET index for the own document. */
499 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) = 0;
501 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
502 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
503 XclExpRefLogEntry
* pRefLogEntry
) = 0;
505 /** Derived classes store all cells in the given range in a CRN record list. */
506 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) = 0;
508 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) = 0;
509 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) = 0;
511 /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
512 virtual bool InsertAddIn(
513 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
514 const OUString
& rName
) = 0;
515 /** InsertEuroTool */
516 virtual bool InsertEuroTool(
517 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
518 const OUString
& rName
) = 0;
520 /** Derived classes find or insert an EXTERNNAME record for DDE links. */
521 virtual bool InsertDde(
522 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
523 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) = 0;
525 virtual bool InsertExtName(
526 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rUrl
,
527 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
) = 0;
529 /** Derived classes write the entire link table to the passed stream. */
530 virtual void Save( XclExpStream
& rStrm
) = 0;
532 /** Derived classes write the entire link table to the passed OOXML stream. */
533 virtual void SaveXml( XclExpXmlStream
& rStrm
) = 0;
536 explicit XclExpLinkManagerImpl( const XclExpRoot
& rRoot
);
541 /** Implementation of the link manager for BIFF5/BIFF7. */
542 class XclExpLinkManagerImpl5
: public XclExpLinkManagerImpl
545 explicit XclExpLinkManagerImpl5( const XclExpRoot
& rRoot
);
547 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
548 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
549 SCTAB nFirstScTab
, SCTAB nLastScTab
,
550 XclExpRefLogEntry
* pRefLogEntry
) override
;
551 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) override
;
553 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
554 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
555 XclExpRefLogEntry
* pRefLogEntry
) override
;
557 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) override
;
559 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) override
;
560 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) override
;
562 virtual bool InsertAddIn(
563 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
564 const OUString
& rName
) override
;
566 /** InsertEuroTool */
567 virtual bool InsertEuroTool(
568 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
569 const OUString
& rName
) override
;
571 virtual bool InsertDde(
572 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
573 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) override
;
575 virtual bool InsertExtName(
576 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rUrl
,
577 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
) override
;
579 virtual void Save( XclExpStream
& rStrm
) override
;
581 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
584 typedef XclExpRecordList
< XclExpExternSheet
> XclExpExtSheetList
;
585 typedef XclExpExtSheetList::RecordRefType XclExpExtSheetRef
;
586 typedef ::std::map
< SCTAB
, sal_uInt16
> XclExpIntTabMap
;
587 typedef ::std::map
< sal_Unicode
, sal_uInt16
> XclExpCodeMap
;
590 /** Returns the number of EXTERNSHEET records. */
591 sal_uInt16
GetExtSheetCount() const;
593 /** Appends an internal EXTERNSHEET record and returns the one-based index. */
594 sal_uInt16
AppendInternal( XclExpExtSheetRef
const & xExtSheet
);
595 /** Creates all EXTERNSHEET records for internal sheets on first call. */
596 void CreateInternal();
598 /** Returns the specified internal EXTERNSHEET record. */
599 XclExpExtSheetRef
GetInternal( sal_uInt16 nExtSheet
);
600 /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
601 XclExpExtSheetRef
FindInternal( sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
, SCTAB nScTab
);
602 /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
603 XclExpExtSheetRef
FindInternal( sal_uInt16
& rnExtSheet
, sal_Unicode cCode
);
606 XclExpExtSheetList maExtSheetList
; /// List with EXTERNSHEET records.
607 XclExpIntTabMap maIntTabMap
; /// Maps internal Calc sheets to EXTERNSHEET records.
608 XclExpCodeMap maCodeMap
; /// Maps special external codes to EXTERNSHEET records.
611 /** Implementation of the link manager for BIFF8 and OOXML. */
612 class XclExpLinkManagerImpl8
: public XclExpLinkManagerImpl
615 explicit XclExpLinkManagerImpl8( const XclExpRoot
& rRoot
);
617 virtual void FindExtSheet( sal_uInt16
& rnExtSheet
,
618 sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
619 SCTAB nFirstScTab
, SCTAB nLastScTab
,
620 XclExpRefLogEntry
* pRefLogEntry
) override
;
621 virtual sal_uInt16
FindExtSheet( sal_Unicode cCode
) override
;
623 virtual void FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
624 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
625 XclExpRefLogEntry
* pRefLogEntry
) override
;
627 virtual void StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
) override
;
629 virtual void StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
) override
;
630 virtual void StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
) override
;
632 virtual bool InsertAddIn(
633 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
634 const OUString
& rName
) override
;
635 /** InsertEuroTool */
636 virtual bool InsertEuroTool(
637 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
638 const OUString
& rName
) override
;
640 virtual bool InsertDde(
641 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
642 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
) override
;
644 virtual bool InsertExtName(
645 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rUrl
,
646 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
) override
;
648 virtual void Save( XclExpStream
& rStrm
) override
;
650 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
653 /** Searches for or inserts a new XTI structure.
654 @return The 0-based list index of the XTI structure. */
655 sal_uInt16
InsertXti( const XclExpXti
& rXti
);
659 XclExpSupbookBuffer maSBBuffer
; /// List of all SUPBOOK records.
660 std::vector
< XclExpXti
> maXtiVec
; /// List of XTI structures for the EXTERNSHEET record.
665 // *** Implementation ***
667 // Excel sheet indexes ========================================================
670 XclExpTabInfo::XclExpTabInfo( const XclExpRoot
& rRoot
) :
677 mnFirstVisXclTab( 0 )
679 ScDocument
& rDoc
= GetDoc();
680 ScExtDocOptions
& rDocOpt
= GetExtDocOptions();
682 mnScCnt
= rDoc
.GetTableCount();
685 SCTAB nFirstVisScTab
= SCTAB_INVALID
; // first visible sheet
686 SCTAB nFirstExpScTab
= SCTAB_INVALID
; // first exported sheet
688 // --- initialize the flags in the index buffer ---
690 maTabInfoVec
.resize( mnScCnt
);
691 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
693 // ignored sheets (skipped by export, with invalid Excel sheet index)
694 if( rDoc
.IsScenario( nScTab
) )
696 SetFlag( nScTab
, ExcTabBufFlags::Ignore
);
699 // external sheets (skipped, but with valid Excel sheet index for ref's)
700 else if( rDoc
.GetLinkMode( nScTab
) == ScLinkMode::VALUE
)
702 SetFlag( nScTab
, ExcTabBufFlags::Extern
);
709 rDoc
.GetName( nScTab
, maTabInfoVec
[ nScTab
].maScName
);
711 // remember first exported sheet
712 if( nFirstExpScTab
== SCTAB_INVALID
)
713 nFirstExpScTab
= nScTab
;
714 // remember first visible exported sheet
715 if( (nFirstVisScTab
== SCTAB_INVALID
) && rDoc
.IsVisible( nScTab
) )
716 nFirstVisScTab
= nScTab
;
718 // sheet visible (only exported sheets)
719 SetFlag( nScTab
, ExcTabBufFlags::Visible
, rDoc
.IsVisible( nScTab
) );
721 // sheet selected (only exported sheets)
722 if( const ScExtTabSettings
* pTabSett
= rDocOpt
.GetTabSettings( nScTab
) )
723 SetFlag( nScTab
, ExcTabBufFlags::Selected
, pTabSett
->mbSelected
);
725 // sheet mirrored (only exported sheets)
726 SetFlag( nScTab
, ExcTabBufFlags::Mirrored
, rDoc
.IsLayoutRTL( nScTab
) );
730 // --- visible/selected sheets ---
732 SCTAB nDisplScTab
= rDocOpt
.GetDocSettings().mnDisplTab
;
734 // missing viewdata at embedded XLSX OLE objects
735 if (nDisplScTab
== -1 )
736 nDisplScTab
= rDoc
.GetVisibleTab();
738 // find first visible exported sheet
739 if( (nFirstVisScTab
== SCTAB_INVALID
) || !IsExportTab( nFirstVisScTab
) )
741 // no exportable visible sheet -> use first exportable sheet
742 nFirstVisScTab
= nFirstExpScTab
;
743 if( (nFirstVisScTab
== SCTAB_INVALID
) || !IsExportTab( nFirstVisScTab
) )
745 // no exportable sheet at all -> use active sheet and export it
746 nFirstVisScTab
= nDisplScTab
;
747 SetFlag( nFirstVisScTab
, ExcTabBufFlags::SkipMask
, false ); // clear skip flags
749 SetFlag( nFirstVisScTab
, ExcTabBufFlags::Visible
); // must be visible, even if originally hidden
752 // find currently displayed sheet
753 if( !IsExportTab( nDisplScTab
) ) // selected sheet not exported (i.e. scenario) -> use first visible
754 nDisplScTab
= nFirstVisScTab
;
755 SetFlag( nDisplScTab
, ExcTabBufFlags::Visible
| ExcTabBufFlags::Selected
);
757 // number of selected sheets
758 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
759 if( IsSelectedTab( nScTab
) )
762 // --- calculate resulting Excel sheet indexes ---
765 mnFirstVisXclTab
= GetXclTab( nFirstVisScTab
);
766 mnDisplXclTab
= GetXclTab( nDisplScTab
);
768 // --- sorted vectors for index lookup ---
773 bool XclExpTabInfo::IsExportTab( SCTAB nScTab
) const
775 /* Check sheet index before to avoid assertion in GetFlag(). */
776 return (nScTab
< mnScCnt
&& nScTab
>= 0) && !GetFlag( nScTab
, ExcTabBufFlags::SkipMask
);
779 bool XclExpTabInfo::IsExternalTab( SCTAB nScTab
) const
781 /* Check sheet index before to avoid assertion (called from formula
782 compiler also for deleted references). */
783 return (nScTab
< mnScCnt
&& nScTab
>= 0) && GetFlag( nScTab
, ExcTabBufFlags::Extern
);
786 bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab
) const
788 return GetFlag( nScTab
, ExcTabBufFlags::Visible
);
791 bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab
) const
793 return GetFlag( nScTab
, ExcTabBufFlags::Selected
);
796 bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab
) const
798 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
799 return GetXclTab( nScTab
) == mnDisplXclTab
;
802 bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab
) const
804 return GetFlag( nScTab
, ExcTabBufFlags::Mirrored
);
807 OUString
XclExpTabInfo::GetScTabName( SCTAB nScTab
) const
809 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
810 return (nScTab
< mnScCnt
&& nScTab
>= 0) ? maTabInfoVec
[ nScTab
].maScName
: OUString();
813 sal_uInt16
XclExpTabInfo::GetXclTab( SCTAB nScTab
) const
815 return (nScTab
< mnScCnt
&& nScTab
>= 0) ? maTabInfoVec
[ nScTab
].mnXclTab
: EXC_TAB_DELETED
;
818 SCTAB
XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab
) const
820 OSL_ENSURE( nSortedScTab
< mnScCnt
&& nSortedScTab
>= 0, "XclExpTabInfo::GetRealScTab - sheet out of range" );
821 return (nSortedScTab
< mnScCnt
&& nSortedScTab
>= 0) ? maFromSortedVec
[ nSortedScTab
] : SCTAB_INVALID
;
824 bool XclExpTabInfo::GetFlag( SCTAB nScTab
, ExcTabBufFlags nFlags
) const
826 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::GetFlag - sheet out of range" );
827 return (nScTab
< mnScCnt
&& nScTab
>= 0) && (maTabInfoVec
[ nScTab
].mnFlags
& nFlags
);
830 void XclExpTabInfo::SetFlag( SCTAB nScTab
, ExcTabBufFlags nFlags
, bool bSet
)
832 OSL_ENSURE( nScTab
< mnScCnt
&& nScTab
>= 0, "XclExpTabInfo::SetFlag - sheet out of range" );
833 if( nScTab
< mnScCnt
&& nScTab
>= 0 )
836 maTabInfoVec
[ nScTab
].mnFlags
|= nFlags
;
838 maTabInfoVec
[ nScTab
].mnFlags
&= ~nFlags
;
842 void XclExpTabInfo::CalcXclIndexes()
844 sal_uInt16 nXclTab
= 0;
847 // --- pass 1: process regular sheets ---
848 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
850 if( IsExportTab( nScTab
) )
852 maTabInfoVec
[ nScTab
].mnXclTab
= nXclTab
;
856 maTabInfoVec
[ nScTab
].mnXclTab
= EXC_TAB_DELETED
;
860 // --- pass 2: process external sheets (nXclTab continues) ---
861 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
863 if( IsExternalTab( nScTab
) )
865 maTabInfoVec
[ nScTab
].mnXclTab
= nXclTab
;
871 // result: first occur all exported sheets, followed by all external sheets
874 typedef ::std::pair
< OUString
, SCTAB
> XclExpTabName
;
878 struct XclExpTabNameSort
{
879 bool operator ()( const XclExpTabName
& rArg1
, const XclExpTabName
& rArg2
)
881 // compare the sheet names only
882 return ScGlobal::GetCollator().compareString( rArg1
.first
, rArg2
.first
) < 0;
888 void XclExpTabInfo::CalcSortedIndexes()
890 ScDocument
& rDoc
= GetDoc();
891 ::std::vector
< XclExpTabName
> aVec( mnScCnt
);
894 // fill with sheet names
895 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
897 rDoc
.GetName( nScTab
, aVec
[ nScTab
].first
);
898 aVec
[ nScTab
].second
= nScTab
;
900 ::std::sort( aVec
.begin(), aVec
.end(), XclExpTabNameSort() );
902 // fill index vectors from sorted sheet name vector
903 maFromSortedVec
.resize( mnScCnt
);
904 maToSortedVec
.resize( mnScCnt
);
905 for( nScTab
= 0; nScTab
< mnScCnt
; ++nScTab
)
907 maFromSortedVec
[ nScTab
] = aVec
[ nScTab
].second
;
908 maToSortedVec
[ aVec
[ nScTab
].second
] = nScTab
;
912 // External names =============================================================
914 XclExpExtNameBase::XclExpExtNameBase(
915 const XclExpRoot
& rRoot
, const OUString
& rName
, sal_uInt16 nFlags
) :
916 XclExpRecord( EXC_ID_EXTERNNAME
),
919 mxName( XclExpStringHelper::CreateString( rRoot
, rName
, XclStrFlags::EightBitLength
) ),
922 OSL_ENSURE( maName
.getLength() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
923 SetRecSize( 6 + mxName
->GetSize() );
926 void XclExpExtNameBase::WriteBody( XclExpStream
& rStrm
)
931 WriteAddData( rStrm
);
934 void XclExpExtNameBase::WriteAddData( XclExpStream
& /*rStrm*/ )
938 XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot
& rRoot
, const OUString
& rName
) :
939 XclExpExtNameBase( rRoot
, rName
)
944 void XclExpExtNameAddIn::WriteAddData( XclExpStream
& rStrm
)
946 // write a #REF! error formula
947 rStrm
<< sal_uInt16( 2 ) << EXC_TOKID_ERR
<< EXC_ERR_REF
;
950 XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot
& rRoot
,
951 const OUString
& rName
, sal_uInt16 nFlags
, const ScMatrix
* pResults
) :
952 XclExpExtNameBase( rRoot
, rName
, nFlags
)
956 mxMatrix
= std::make_shared
<XclExpCachedMatrix
>( *pResults
);
957 AddRecSize( mxMatrix
->GetSize() );
961 void XclExpExtNameDde::WriteAddData( XclExpStream
& rStrm
)
964 mxMatrix
->Save( rStrm
);
967 XclExpExtName::XclExpExtName( const XclExpRoot
& rRoot
, const XclExpSupbook
& rSupbook
,
968 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
) :
969 XclExpExtNameBase( rRoot
, rName
),
971 mpArray(rArray
->Clone())
975 void XclExpExtName::WriteAddData( XclExpStream
& rStrm
)
977 // Write only if it only has a single token that is either a cell or cell
978 // range address. Excel just writes '02 00 1C 17' for all the other types
979 // of external names.
981 using namespace ::formula
;
984 if (mpArray
->GetLen() != 1)
987 const formula::FormulaToken
* p
= mpArray
->FirstToken();
988 if (!p
->IsExternalRef())
991 switch (p
->GetType())
993 case svExternalSingleRef
:
995 const ScSingleRefData
& rRef
= *p
->GetSingleRef();
999 bool bColRel
= rRef
.IsColRel();
1000 bool bRowRel
= rRef
.IsRowRel();
1001 sal_uInt16 nCol
= static_cast<sal_uInt16
>(rRef
.Col());
1002 sal_uInt16 nRow
= static_cast<sal_uInt16
>(rRef
.Row());
1003 if (bColRel
) nCol
|= 0x4000;
1004 if (bRowRel
) nCol
|= 0x8000;
1006 OUString aTabName
= p
->GetString().getString();
1007 sal_uInt16 nSBTab
= mrSupbook
.GetTabIndex(aTabName
);
1010 rStrm
<< static_cast<sal_uInt16
>(9);
1011 // operator token (3A for cell reference)
1012 rStrm
<< static_cast<sal_uInt8
>(0x3A);
1013 // cell address (Excel's address has 2 sheet IDs.)
1014 rStrm
<< nSBTab
<< nSBTab
<< nRow
<< nCol
;
1017 case svExternalDoubleRef
:
1019 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
1020 const ScSingleRefData
& r1
= rRef
.Ref1
;
1021 const ScSingleRefData
& r2
= rRef
.Ref2
;
1022 if (r1
.IsTabRel() || r2
.IsTabRel())
1025 sal_uInt16 nTab1
= r1
.Tab();
1026 sal_uInt16 nTab2
= r2
.Tab();
1027 bool bCol1Rel
= r1
.IsColRel();
1028 bool bRow1Rel
= r1
.IsRowRel();
1029 bool bCol2Rel
= r2
.IsColRel();
1030 bool bRow2Rel
= r2
.IsRowRel();
1032 sal_uInt16 nCol1
= static_cast<sal_uInt16
>(r1
.Col());
1033 sal_uInt16 nCol2
= static_cast<sal_uInt16
>(r2
.Col());
1034 sal_uInt16 nRow1
= static_cast<sal_uInt16
>(r1
.Row());
1035 sal_uInt16 nRow2
= static_cast<sal_uInt16
>(r2
.Row());
1036 if (bCol1Rel
) nCol1
|= 0x4000;
1037 if (bRow1Rel
) nCol1
|= 0x8000;
1038 if (bCol2Rel
) nCol2
|= 0x4000;
1039 if (bRow2Rel
) nCol2
|= 0x8000;
1041 OUString aTabName
= p
->GetString().getString();
1042 sal_uInt16 nSBTab
= mrSupbook
.GetTabIndex(aTabName
);
1044 // size is always 13 (0x0D)
1045 rStrm
<< static_cast<sal_uInt16
>(13);
1046 // operator token (3B for area reference)
1047 rStrm
<< static_cast<sal_uInt8
>(0x3B);
1048 // range (area) address
1049 sal_uInt16 nSBTab2
= nSBTab
+ nTab2
- nTab1
;
1050 rStrm
<< nSBTab
<< nSBTab2
<< nRow1
<< nRow2
<< nCol1
<< nCol2
;
1059 // special value for #REF! (02 00 1C 17)
1060 rStrm
<< static_cast<sal_uInt16
>(2) << EXC_TOKID_ERR
<< EXC_ERR_REF
;
1063 void XclExpExtName::SaveXml(XclExpXmlStream
& rStrm
)
1065 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.GetCurrentStream();
1067 /* TODO: mpArray contains external references. It doesn't cause any problems, but it's enough
1068 to export it without the external document identifier. */
1069 if (mpArray
->GetLen())
1071 const OUString aFormula
= XclXmlUtils::ToOUString(GetCompileFormulaContext(), ScAddress(0, 0, 0), mpArray
.get());
1072 pExternalLink
->startElement(XML_definedName
,
1073 XML_name
, maName
.toUtf8(),
1074 XML_refersTo
, aFormula
.toUtf8(),
1075 XML_sheetId
, nullptr);
1079 pExternalLink
->startElement(XML_definedName
,
1080 XML_name
, maName
.toUtf8(),
1081 XML_refersTo
, nullptr,
1082 XML_sheetId
, nullptr);
1085 pExternalLink
->endElement(XML_definedName
);
1088 // List of external names =====================================================
1090 XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot
& rRoot
) :
1095 sal_uInt16
XclExpExtNameBuffer::InsertAddIn( const OUString
& rName
)
1097 sal_uInt16 nIndex
= GetIndex( rName
);
1098 return nIndex
? nIndex
: AppendNew( new XclExpExtNameAddIn( GetRoot(), rName
) );
1101 sal_uInt16
XclExpExtNameBuffer::InsertEuroTool( const OUString
& rName
)
1103 sal_uInt16 nIndex
= GetIndex( rName
);
1104 return nIndex
? nIndex
: AppendNew( new XclExpExtNameBase( GetRoot(), rName
) );
1107 sal_uInt16
XclExpExtNameBuffer::InsertDde(
1108 std::u16string_view rApplic
, std::u16string_view rTopic
, const OUString
& rItem
)
1110 sal_uInt16 nIndex
= GetIndex( rItem
);
1114 if( GetDoc().FindDdeLink( rApplic
, rTopic
, rItem
, SC_DDE_IGNOREMODE
, nPos
) )
1116 // create the leading 'StdDocumentName' EXTERNNAME record
1117 if( maNameList
.IsEmpty() )
1118 AppendNew( new XclExpExtNameDde(
1119 GetRoot(), "StdDocumentName", EXC_EXTN_EXPDDE_STDDOC
) );
1121 // try to find DDE result array, but create EXTERNNAME record without them too
1122 const ScMatrix
* pScMatrix
= GetDoc().GetDdeLinkResultMatrix( nPos
);
1123 nIndex
= AppendNew( new XclExpExtNameDde( GetRoot(), rItem
, EXC_EXTN_EXPDDE
, pScMatrix
) );
1129 sal_uInt16
XclExpExtNameBuffer::InsertExtName( const XclExpSupbook
& rSupbook
,
1130 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
1132 sal_uInt16 nIndex
= GetIndex( rName
);
1133 return nIndex
? nIndex
: AppendNew( new XclExpExtName( GetRoot(), rSupbook
, rName
, rArray
) );
1136 void XclExpExtNameBuffer::Save( XclExpStream
& rStrm
)
1138 maNameList
.Save( rStrm
);
1141 void XclExpExtNameBuffer::SaveXml(XclExpXmlStream
& rStrm
)
1143 maNameList
.SaveXml(rStrm
);
1146 sal_uInt16
XclExpExtNameBuffer::GetIndex( std::u16string_view rName
) const
1148 for( size_t nPos
= 0, nSize
= maNameList
.GetSize(); nPos
< nSize
; ++nPos
)
1149 if( maNameList
.GetRecord( nPos
)->GetName() == rName
)
1150 return static_cast< sal_uInt16
>( nPos
+ 1 );
1154 sal_uInt16
XclExpExtNameBuffer::AppendNew( XclExpExtNameBase
* pExtName
)
1156 size_t nSize
= maNameList
.GetSize();
1157 if( nSize
< 0x7FFF )
1159 maNameList
.AppendRecord( pExtName
);
1160 return static_cast< sal_uInt16
>( nSize
+ 1 );
1165 // Cached external cells ======================================================
1167 XclExpCrn::XclExpCrn( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
) :
1168 XclExpRecord( EXC_ID_CRN
, 4 ),
1172 maValues
.push_back( rValue
);
1175 bool XclExpCrn::InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
)
1177 if( (nScRow
!= mnScRow
) || (nScCol
!= static_cast< SCCOL
>( mnScCol
+ maValues
.size() )) )
1179 maValues
.push_back( rValue
);
1183 void XclExpCrn::WriteBody( XclExpStream
& rStrm
)
1185 rStrm
<< static_cast< sal_uInt8
>( mnScCol
+ maValues
.size() - 1 )
1186 << static_cast< sal_uInt8
>( mnScCol
)
1187 << static_cast< sal_uInt16
>( mnScRow
);
1188 for( const auto& rValue
: maValues
)
1190 if( rValue
.has
< bool >() )
1191 WriteBool( rStrm
, rValue
.get
< bool >() );
1192 else if( rValue
.has
< double >() )
1193 WriteDouble( rStrm
, rValue
.get
< double >() );
1194 else if( rValue
.has
< OUString
>() )
1195 WriteString( rStrm
, rValue
.get
< OUString
>() );
1197 WriteEmpty( rStrm
);
1201 void XclExpCrn::WriteBool( XclExpStream
& rStrm
, bool bValue
)
1203 rStrm
<< EXC_CACHEDVAL_BOOL
<< sal_uInt8( bValue
? 1 : 0);
1204 rStrm
.WriteZeroBytes( 7 );
1207 void XclExpCrn::WriteDouble( XclExpStream
& rStrm
, double fValue
)
1209 if( !std::isfinite( fValue
) )
1211 FormulaError nScError
= GetDoubleErrorValue(fValue
);
1212 WriteError( rStrm
, XclTools::GetXclErrorCode( nScError
) );
1216 rStrm
<< EXC_CACHEDVAL_DOUBLE
<< fValue
;
1220 void XclExpCrn::WriteString( XclExpStream
& rStrm
, const OUString
& rValue
)
1222 rStrm
<< EXC_CACHEDVAL_STRING
<< XclExpString( rValue
);
1225 void XclExpCrn::WriteError( XclExpStream
& rStrm
, sal_uInt8 nErrCode
)
1227 rStrm
<< EXC_CACHEDVAL_ERROR
<< nErrCode
;
1228 rStrm
.WriteZeroBytes( 7 );
1231 void XclExpCrn::WriteEmpty( XclExpStream
& rStrm
)
1233 rStrm
<< EXC_CACHEDVAL_EMPTY
;
1234 rStrm
.WriteZeroBytes( 8 );
1237 void XclExpCrn::SaveXml( XclExpXmlStream
& rStrm
)
1239 sax_fastparser::FSHelperPtr pFS
= rStrm
.GetCurrentStream();
1241 pFS
->startElement(XML_row
, XML_r
, OString::number(mnScRow
+ 1));
1243 ScAddress
aAdr( mnScCol
, mnScRow
, 0); // Tab number doesn't matter
1244 for( const auto& rValue
: maValues
)
1246 bool bCloseCell
= true;
1247 if( rValue
.has
< double >() )
1249 double fVal
= rValue
.get
< double >();
1250 if (std::isfinite( fVal
))
1253 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aAdr
));
1254 pFS
->startElement(XML_v
);
1259 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aAdr
), XML_t
, "e");
1260 pFS
->startElement(XML_v
);
1261 pFS
->write( "#VALUE!" ); // OOXTODO: support other error values
1264 else if( rValue
.has
< OUString
>() )
1266 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aAdr
), XML_t
, "str");
1267 pFS
->startElement(XML_v
);
1268 pFS
->write( rValue
.get
< OUString
>() );
1270 else if( rValue
.has
< bool >() )
1272 pFS
->startElement(XML_cell
, XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aAdr
), XML_t
, "b");
1273 pFS
->startElement(XML_v
);
1274 pFS
->write( rValue
.get
< bool >() ? "1" : "0" );
1276 // OOXTODO: error type cell t='e'
1279 // Empty/blank cell not stored, only aAdr is incremented.
1284 pFS
->endElement(XML_v
);
1285 pFS
->endElement(XML_cell
);
1290 pFS
->endElement( XML_row
);
1293 // Cached cells of a sheet ====================================================
1295 XclExpXct::XclExpXct( const XclExpRoot
& rRoot
, const OUString
& rTabName
,
1296 sal_uInt16 nSBTab
, ScExternalRefCache::TableTypeRef
const & xCacheTable
) :
1297 XclExpRoot( rRoot
),
1298 mxCacheTable( xCacheTable
),
1299 maUsedCells( rRoot
.GetDoc().GetSheetLimits() ),
1300 maBoundRange( ScAddress::INITIALIZE_INVALID
),
1301 maTabName( rTabName
),
1306 void XclExpXct::StoreCellRange( const ScRange
& rRange
)
1308 // #i70418# restrict size of external range to prevent memory overflow
1309 if( (rRange
.aEnd
.Col() - rRange
.aStart
.Col()) * (rRange
.aEnd
.Row() - rRange
.aStart
.Row()) > 1024 )
1312 maUsedCells
.SetMultiMarkArea( rRange
);
1313 maBoundRange
.ExtendTo( rRange
);
1316 void XclExpXct::StoreCell_( const ScAddress
& rCell
)
1318 maUsedCells
.SetMultiMarkArea( ScRange( rCell
) );
1319 maBoundRange
.ExtendTo( ScRange( rCell
) );
1322 void XclExpXct::StoreCellRange_( const ScRange
& rRange
)
1324 maUsedCells
.SetMultiMarkArea( rRange
);
1325 maBoundRange
.ExtendTo( rRange
);
1330 class XclExpCrnList
: public XclExpRecordList
< XclExpCrn
>
1333 /** Inserts the passed value into an existing or new CRN record.
1334 @return True = value inserted successfully, false = CRN list is full. */
1335 bool InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
);
1338 bool XclExpCrnList::InsertValue( SCCOL nScCol
, SCROW nScRow
, const Any
& rValue
)
1340 RecordRefType xLastRec
= GetLastRecord();
1341 if( xLastRec
&& xLastRec
->InsertValue( nScCol
, nScRow
, rValue
) )
1343 if( GetSize() == SAL_MAX_UINT16
)
1345 AppendNewRecord( new XclExpCrn( nScCol
, nScRow
, rValue
) );
1351 bool XclExpXct::BuildCrnList( XclExpCrnList
& rCrnRecs
)
1356 /* Get the range of used rows in the cache table. This may help to
1357 optimize building the CRN record list if the cache table does not
1358 contain all referred cells, e.g. if big empty ranges are used in the
1360 ::std::pair
< SCROW
, SCROW
> aRowRange
= mxCacheTable
->getRowRange();
1361 if( aRowRange
.first
>= aRowRange
.second
)
1364 /* Crop the bounding range of used cells in this table to Excel limits.
1365 Return if there is no external cell inside these limits. */
1366 if( !GetAddressConverter().ValidateRange( maBoundRange
, false ) )
1369 /* Find the resulting row range that needs to be processed. */
1370 SCROW nScRow1
= ::std::max( aRowRange
.first
, maBoundRange
.aStart
.Row() );
1371 SCROW nScRow2
= ::std::min( aRowRange
.second
- 1, maBoundRange
.aEnd
.Row() );
1372 if( nScRow1
> nScRow2
)
1375 /* Build and collect all CRN records before writing the XCT record. This
1376 is needed to determine the total number of CRN records which must be
1377 known when writing the XCT record (possibly encrypted, so seeking the
1378 output stream back after writing the CRN records is not an option). */
1379 SvNumberFormatter
& rFormatter
= GetFormatter();
1381 for( SCROW nScRow
= nScRow1
; bValid
&& (nScRow
<= nScRow2
); ++nScRow
)
1383 ::std::pair
< SCCOL
, SCCOL
> aColRange
= mxCacheTable
->getColRange( nScRow
);
1384 const SCCOL nScEnd
= ::std::min( aColRange
.second
, GetDoc().GetSheetLimits().GetMaxColCount() );
1385 for( SCCOL nScCol
= aColRange
.first
; bValid
&& (nScCol
< nScEnd
); ++nScCol
)
1387 if( maUsedCells
.IsCellMarked( nScCol
, nScRow
, true ) )
1389 sal_uInt32 nScNumFmt
= 0;
1390 ScExternalRefCache::TokenRef xToken
= mxCacheTable
->getCell( nScCol
, nScRow
, &nScNumFmt
);
1391 using namespace ::formula
;
1393 switch( xToken
->GetType() )
1396 bValid
= (rFormatter
.GetType( nScNumFmt
) == SvNumFormatType::LOGICAL
) ?
1397 rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetDouble() != 0 ) ) :
1398 rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetDouble() ) );
1401 // do not save empty strings (empty cells) to cache
1402 if( !xToken
->GetString().isEmpty() )
1403 bValid
= rCrnRecs
.InsertValue( nScCol
, nScRow
, Any( xToken
->GetString().getString() ) );
1414 void XclExpXct::Save( XclExpStream
& rStrm
)
1416 XclExpCrnList aCrnRecs
;
1417 if (!BuildCrnList( aCrnRecs
))
1420 // write the XCT record and the list of CRN records
1421 rStrm
.StartRecord( EXC_ID_XCT
, 4 );
1422 rStrm
<< static_cast< sal_uInt16
>( aCrnRecs
.GetSize() ) << mnSBTab
;
1424 aCrnRecs
.Save( rStrm
);
1427 void XclExpXct::SaveXml( XclExpXmlStream
& rStrm
)
1429 XclExpCrnList aCrnRecs
;
1431 sax_fastparser::FSHelperPtr pFS
= rStrm
.GetCurrentStream();
1433 bool bValid
= BuildCrnList( aCrnRecs
);
1434 pFS
->startElement(XML_sheetData
, XML_sheetId
, OString::number(mnSBTab
));
1438 aCrnRecs
.SaveXml( rStrm
);
1440 pFS
->endElement( XML_sheetData
);
1443 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
1445 XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot
& rRoot
, sal_uInt16 nRecId
, sal_uInt32 nRecSize
) :
1446 XclExpRecord( nRecId
, nRecSize
),
1451 XclExpExtNameBuffer
& XclExpExternSheetBase::GetExtNameBuffer()
1454 mxExtNameBfr
= std::make_shared
<XclExpExtNameBuffer
>( GetRoot() );
1455 return *mxExtNameBfr
;
1458 void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream
& rStrm
)
1461 mxExtNameBfr
->Save( rStrm
);
1464 void XclExpExternSheetBase::WriteExtNameBufferXml( XclExpXmlStream
& rStrm
)
1467 mxExtNameBfr
->SaveXml( rStrm
);
1470 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
1472 XclExpExternSheet::XclExpExternSheet( const XclExpRoot
& rRoot
, sal_Unicode cCode
) :
1473 XclExpExternSheetBase( rRoot
, EXC_ID_EXTERNSHEET
)
1475 Init( OUStringChar(cCode
) );
1478 XclExpExternSheet::XclExpExternSheet( const XclExpRoot
& rRoot
, std::u16string_view rTabName
) :
1479 XclExpExternSheetBase( rRoot
, EXC_ID_EXTERNSHEET
)
1481 // reference to own sheet: \03<sheetname>
1482 Init(OUStringConcatenation(OUStringChar(EXC_EXTSH_TABNAME
) + rTabName
));
1485 void XclExpExternSheet::Save( XclExpStream
& rStrm
)
1487 // EXTERNSHEET record
1488 XclExpRecord::Save( rStrm
);
1489 // EXTERNNAME records
1490 WriteExtNameBuffer( rStrm
);
1493 void XclExpExternSheet::Init( std::u16string_view rEncUrl
)
1495 OSL_ENSURE_BIFF( GetBiff() <= EXC_BIFF5
);
1496 maTabName
.AssignByte( rEncUrl
, GetTextEncoding(), XclStrFlags::EightBitLength
);
1497 SetRecSize( maTabName
.GetSize() );
1500 sal_uInt16
XclExpExternSheet::InsertAddIn( const OUString
& rName
)
1502 return GetExtNameBuffer().InsertAddIn( rName
);
1505 void XclExpExternSheet::WriteBody( XclExpStream
& rStrm
)
1507 sal_uInt8 nNameSize
= static_cast< sal_uInt8
>( maTabName
.Len() );
1508 // special case: reference to own sheet (starting with '\03') needs wrong string length
1509 if( maTabName
.GetChar( 0 ) == EXC_EXTSH_TABNAME
)
1512 maTabName
.WriteBuffer( rStrm
);
1515 // External document (SUPBOOK, BIFF8) =========================================
1517 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, sal_uInt16 nXclTabCount
) :
1518 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1519 meType( XclSupbookType::Self
),
1520 mnXclTabCount( nXclTabCount
),
1525 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
) :
1526 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1527 meType( XclSupbookType::Addin
),
1533 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
, XclSupbookType
) :
1534 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
),
1536 maUrlEncoded( rUrl
),
1537 meType( XclSupbookType::Eurotool
),
1541 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1544 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rUrl
) :
1545 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
),
1547 maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot
, rUrl
) ),
1548 meType( XclSupbookType::Extern
),
1552 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1554 // We need to create all tables up front to ensure the correct table order.
1555 ScExternalRefManager
* pRefMgr
= rRoot
.GetDoc().GetExternalRefManager();
1556 sal_uInt16 nFileId
= pRefMgr
->getExternalFileId( rUrl
);
1557 mnFileId
= nFileId
+ 1;
1558 ScfStringVec aTabNames
;
1559 pRefMgr
->getAllCachedTableNames( nFileId
, aTabNames
);
1560 size_t nTabIndex
= 0;
1561 for( const auto& rTabName
: aTabNames
)
1563 InsertTabName( rTabName
, pRefMgr
->getCacheTable( nFileId
, nTabIndex
) );
1568 XclExpSupbook::XclExpSupbook( const XclExpRoot
& rRoot
, const OUString
& rApplic
, const OUString
& rTopic
) :
1569 XclExpExternSheetBase( rRoot
, EXC_ID_SUPBOOK
, 4 ),
1571 maDdeTopic( rTopic
),
1572 maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic
, rTopic
) ),
1573 meType( XclSupbookType::Special
),
1577 SetRecSize( 2 + maUrlEncoded
.GetSize() );
1580 bool XclExpSupbook::IsUrlLink( std::u16string_view rUrl
) const
1582 return (meType
== XclSupbookType::Extern
|| meType
== XclSupbookType::Eurotool
) && (maUrl
== rUrl
);
1585 bool XclExpSupbook::IsDdeLink( std::u16string_view rApplic
, std::u16string_view rTopic
) const
1587 return (meType
== XclSupbookType::Special
) && (maUrl
== rApplic
) && (maDdeTopic
== rTopic
);
1590 void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry
& rRefLogEntry
,
1591 sal_uInt16 nFirstSBTab
, sal_uInt16 nLastSBTab
) const
1593 rRefLogEntry
.mpUrl
= maUrlEncoded
.IsEmpty() ? nullptr : &maUrlEncoded
;
1594 rRefLogEntry
.mpFirstTab
= GetTabName( nFirstSBTab
);
1595 rRefLogEntry
.mpLastTab
= GetTabName( nLastSBTab
);
1598 void XclExpSupbook::StoreCellRange( const ScRange
& rRange
, sal_uInt16 nSBTab
)
1600 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1601 pXct
->StoreCellRange( rRange
);
1604 void XclExpSupbook::StoreCell_( sal_uInt16 nSBTab
, const ScAddress
& rCell
)
1606 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1607 pXct
->StoreCell_( rCell
);
1610 void XclExpSupbook::StoreCellRange_( sal_uInt16 nSBTab
, const ScRange
& rRange
)
1612 // multi-table range is not allowed!
1613 if( rRange
.aStart
.Tab() == rRange
.aEnd
.Tab() )
1614 if( XclExpXct
* pXct
= maXctList
.GetRecord( nSBTab
) )
1615 pXct
->StoreCellRange_( rRange
);
1618 sal_uInt16
XclExpSupbook::GetTabIndex( const OUString
& rTabName
) const
1620 XclExpString
aXclName(rTabName
);
1621 size_t nSize
= maXctList
.GetSize();
1622 for (size_t i
= 0; i
< nSize
; ++i
)
1624 XclExpXctRef aRec
= maXctList
.GetRecord(i
);
1625 if (aXclName
== aRec
->GetTabName())
1626 return ulimit_cast
<sal_uInt16
>(i
);
1631 sal_uInt16
XclExpSupbook::GetTabCount() const
1633 return ulimit_cast
<sal_uInt16
>(maXctList
.GetSize());
1636 sal_uInt16
XclExpSupbook::InsertTabName( const OUString
& rTabName
, ScExternalRefCache::TableTypeRef
const & xCacheTable
)
1638 SAL_WARN_IF( meType
!= XclSupbookType::Extern
, "sc.filter", "Don't insert sheet names here" );
1639 sal_uInt16 nSBTab
= ulimit_cast
< sal_uInt16
>( maXctList
.GetSize() );
1640 XclExpXctRef xXct
= new XclExpXct( GetRoot(), rTabName
, nSBTab
, xCacheTable
);
1641 AddRecSize( xXct
->GetTabName().GetSize() );
1642 maXctList
.AppendRecord( xXct
);
1646 sal_uInt16
XclExpSupbook::InsertAddIn( const OUString
& rName
)
1648 return GetExtNameBuffer().InsertAddIn( rName
);
1651 sal_uInt16
XclExpSupbook::InsertEuroTool( const OUString
& rName
)
1653 return GetExtNameBuffer().InsertEuroTool( rName
);
1656 sal_uInt16
XclExpSupbook::InsertDde( const OUString
& rItem
)
1658 return GetExtNameBuffer().InsertDde( maUrl
, maDdeTopic
, rItem
);
1661 sal_uInt16
XclExpSupbook::InsertExtName( const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
1663 return GetExtNameBuffer().InsertExtName(*this, rName
, rArray
);
1666 XclSupbookType
XclExpSupbook::GetType() const
1671 sal_uInt16
XclExpSupbook::GetFileId() const
1676 const OUString
& XclExpSupbook::GetUrl() const
1681 void XclExpSupbook::Save( XclExpStream
& rStrm
)
1684 XclExpRecord::Save( rStrm
);
1685 // XCT record, CRN records
1686 maXctList
.Save( rStrm
);
1687 // EXTERNNAME records
1688 WriteExtNameBuffer( rStrm
);
1691 void XclExpSupbook::SaveXml( XclExpXmlStream
& rStrm
)
1693 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.GetCurrentStream();
1695 // Add relation for this stream, e.g. xl/externalLinks/_rels/externalLink1.xml.rels
1696 sal_uInt16 nLevel
= 0;
1699 // BuildFileName delete ../ and convert them to nLevel
1700 // but addrelation needs ../ instead of nLevel, so we have to convert it back
1701 OUString sFile
= XclExpHyperlink::BuildFileName(nLevel
, bRel
, maUrl
, GetRoot(), true);
1702 while (nLevel
-- > 0)
1703 sFile
= "../" + sFile
;
1705 OUString sId
= rStrm
.addRelation( pExternalLink
->getOutputStream(),
1706 oox::getRelationship(Relationship::EXTERNALLINKPATH
), sFile
, true );
1708 pExternalLink
->startElement( XML_externalLink
,
1709 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)).toUtf8());
1711 pExternalLink
->startElement( XML_externalBook
,
1712 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
1713 FSNS(XML_r
, XML_id
), sId
.toUtf8());
1715 if (!maXctList
.IsEmpty())
1717 pExternalLink
->startElement(XML_sheetNames
);
1718 for (size_t nPos
= 0, nSize
= maXctList
.GetSize(); nPos
< nSize
; ++nPos
)
1720 pExternalLink
->singleElement(XML_sheetName
,
1721 XML_val
, XclXmlUtils::ToOString(maXctList
.GetRecord(nPos
)->GetTabName()));
1723 pExternalLink
->endElement( XML_sheetNames
);
1729 pExternalLink
->startElement(XML_definedNames
);
1730 // externalName elements
1731 WriteExtNameBufferXml( rStrm
);
1732 pExternalLink
->endElement(XML_definedNames
);
1735 if (!maXctList
.IsEmpty())
1737 pExternalLink
->startElement(XML_sheetDataSet
);
1739 // sheetData elements
1740 maXctList
.SaveXml( rStrm
);
1742 pExternalLink
->endElement( XML_sheetDataSet
);
1745 pExternalLink
->endElement( XML_externalBook
);
1746 pExternalLink
->endElement( XML_externalLink
);
1749 const XclExpString
* XclExpSupbook::GetTabName( sal_uInt16 nSBTab
) const
1751 XclExpXctRef xXct
= maXctList
.GetRecord( nSBTab
);
1752 return xXct
? &xXct
->GetTabName() : nullptr;
1755 void XclExpSupbook::WriteBody( XclExpStream
& rStrm
)
1759 case XclSupbookType::Self
:
1760 rStrm
<< mnXclTabCount
<< EXC_SUPB_SELF
;
1762 case XclSupbookType::Extern
:
1763 case XclSupbookType::Special
:
1764 case XclSupbookType::Eurotool
:
1766 sal_uInt16 nCount
= ulimit_cast
< sal_uInt16
>( maXctList
.GetSize() );
1767 rStrm
<< nCount
<< maUrlEncoded
;
1769 for( size_t nPos
= 0, nSize
= maXctList
.GetSize(); nPos
< nSize
; ++nPos
)
1770 rStrm
<< maXctList
.GetRecord( nPos
)->GetTabName();
1773 case XclSupbookType::Addin
:
1774 rStrm
<< mnXclTabCount
<< EXC_SUPB_ADDIN
;
1777 SAL_WARN( "sc.filter", "Unhandled SUPBOOK type " << meType
);
1781 // All SUPBOOKS in a document =================================================
1783 XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot
& rRoot
) :
1784 XclExpRoot( rRoot
),
1785 mnOwnDocSB( SAL_MAX_UINT16
),
1786 mnAddInSB( SAL_MAX_UINT16
)
1788 XclExpTabInfo
& rTabInfo
= GetTabInfo();
1789 sal_uInt16 nXclCnt
= rTabInfo
.GetXclTabCount();
1790 sal_uInt16 nCodeCnt
= static_cast< sal_uInt16
>( GetExtDocOptions().GetCodeNameCount() );
1791 size_t nCount
= nXclCnt
+ rTabInfo
.GetXclExtTabCount();
1793 OSL_ENSURE( nCount
> 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
1796 maSBIndexVec
.resize( nCount
);
1798 // self-ref SUPBOOK first of list
1799 XclExpSupbookRef xSupbook
= new XclExpSupbook( GetRoot(), ::std::max( nXclCnt
, nCodeCnt
) );
1800 mnOwnDocSB
= Append( xSupbook
);
1801 for( sal_uInt16 nXclTab
= 0; nXclTab
< nXclCnt
; ++nXclTab
)
1802 maSBIndexVec
[ nXclTab
].Set( mnOwnDocSB
, nXclTab
);
1806 XclExpXti
XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab
, sal_uInt16 nLastXclTab
,
1807 XclExpRefLogEntry
* pRefLogEntry
) const
1810 size_t nSize
= maSBIndexVec
.size();
1811 if( (nFirstXclTab
< nSize
) && (nLastXclTab
< nSize
) )
1813 // index of the SUPBOOK record
1814 aXti
.mnSupbook
= maSBIndexVec
[ nFirstXclTab
].mnSupbook
;
1816 // all sheets in the same supbook?
1817 bool bSameSB
= true;
1818 for( sal_uInt16 nXclTab
= nFirstXclTab
+ 1; bSameSB
&& (nXclTab
<= nLastXclTab
); ++nXclTab
)
1820 bSameSB
= maSBIndexVec
[ nXclTab
].mnSupbook
== aXti
.mnSupbook
;
1822 nLastXclTab
= nXclTab
- 1;
1824 aXti
.mnFirstSBTab
= maSBIndexVec
[ nFirstXclTab
].mnSBTab
;
1825 aXti
.mnLastSBTab
= maSBIndexVec
[ nLastXclTab
].mnSBTab
;
1827 // fill external reference log entry (for change tracking)
1830 pRefLogEntry
->mnFirstXclTab
= nFirstXclTab
;
1831 pRefLogEntry
->mnLastXclTab
= nLastXclTab
;
1832 XclExpSupbookRef xSupbook
= maSupbookList
.GetRecord( aXti
.mnSupbook
);
1834 xSupbook
->FillRefLogEntry( *pRefLogEntry
, aXti
.mnFirstSBTab
, aXti
.mnLastSBTab
);
1839 // special range, i.e. for deleted sheets or add-ins
1840 aXti
.mnSupbook
= mnOwnDocSB
;
1841 aXti
.mnFirstSBTab
= nFirstXclTab
;
1842 aXti
.mnLastSBTab
= nLastXclTab
;
1848 void XclExpSupbookBuffer::StoreCellRange( const ScRange
& rRange
)
1850 sal_uInt16 nXclTab
= GetTabInfo().GetXclTab( rRange
.aStart
.Tab() );
1851 if( nXclTab
< maSBIndexVec
.size() )
1853 const XclExpSBIndex
& rSBIndex
= maSBIndexVec
[ nXclTab
];
1854 XclExpSupbookRef xSupbook
= maSupbookList
.GetRecord( rSBIndex
.mnSupbook
);
1855 OSL_ENSURE( xSupbook
, "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
1857 xSupbook
->StoreCellRange( rRange
, rSBIndex
.mnSBTab
);
1863 class FindSBIndexEntry
1866 explicit FindSBIndexEntry(sal_uInt16 nSupbookId
, sal_uInt16 nTabId
) :
1867 mnSupbookId(nSupbookId
), mnTabId(nTabId
) {}
1869 bool operator()(const XclExpSupbookBuffer::XclExpSBIndex
& r
) const
1871 return mnSupbookId
== r
.mnSupbook
&& mnTabId
== r
.mnSBTab
;
1875 sal_uInt16 mnSupbookId
;
1881 void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rCell
)
1883 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
1884 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
1888 XclExpSupbookRef xSupbook
;
1889 sal_uInt16 nSupbookId
;
1890 if (!GetSupbookUrl(xSupbook
, nSupbookId
, *pUrl
))
1892 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
1893 nSupbookId
= Append(xSupbook
);
1896 sal_uInt16 nSheetId
= xSupbook
->GetTabIndex(rTabName
);
1897 if (nSheetId
== EXC_NOTAB
)
1898 // specified table name not found in this SUPBOOK.
1901 FindSBIndexEntry
f(nSupbookId
, nSheetId
);
1902 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
1904 maSBIndexVec
.emplace_back();
1905 XclExpSBIndex
& r
= maSBIndexVec
.back();
1906 r
.mnSupbook
= nSupbookId
;
1907 r
.mnSBTab
= nSheetId
;
1910 xSupbook
->StoreCell_(nSheetId
, rCell
);
1913 void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
1915 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
1916 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
1920 XclExpSupbookRef xSupbook
;
1921 sal_uInt16 nSupbookId
;
1922 if (!GetSupbookUrl(xSupbook
, nSupbookId
, *pUrl
))
1924 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
1925 nSupbookId
= Append(xSupbook
);
1928 SCTAB nTabCount
= rRange
.aEnd
.Tab() - rRange
.aStart
.Tab() + 1;
1930 // If this is a multi-table range, get token for each table.
1931 using namespace ::formula
;
1932 SCTAB aMatrixListSize
= 0;
1934 // This is a new'ed instance, so we must manage its life cycle here.
1935 ScExternalRefCache::TokenArrayRef pArray
= pRefMgr
->getDoubleRefTokens(nFileId
, rTabName
, rRange
, nullptr);
1939 FormulaTokenArrayPlainIterator
aIter(*pArray
);
1940 for (FormulaToken
* p
= aIter
.First(); p
; p
= aIter
.Next())
1942 if (p
->GetType() == svMatrix
)
1944 else if (p
->GetOpCode() != ocSep
)
1946 // This is supposed to be ocSep!!!
1951 if (aMatrixListSize
!= nTabCount
)
1953 // matrix size mismatch!
1957 sal_uInt16 nFirstSheetId
= xSupbook
->GetTabIndex(rTabName
);
1959 ScRange
aRange(rRange
);
1960 aRange
.aStart
.SetTab(0);
1961 aRange
.aEnd
.SetTab(0);
1962 for (SCTAB nTab
= 0; nTab
< nTabCount
; ++nTab
)
1964 sal_uInt16 nSheetId
= nFirstSheetId
+ static_cast<sal_uInt16
>(nTab
);
1965 FindSBIndexEntry
f(nSupbookId
, nSheetId
);
1966 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
1968 maSBIndexVec
.emplace_back();
1969 XclExpSBIndex
& r
= maSBIndexVec
.back();
1970 r
.mnSupbook
= nSupbookId
;
1971 r
.mnSBTab
= nSheetId
;
1974 xSupbook
->StoreCellRange_(nSheetId
, aRange
);
1978 bool XclExpSupbookBuffer::InsertAddIn(
1979 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
, const OUString
& rName
)
1981 XclExpSupbookRef xSupbook
;
1982 if( mnAddInSB
== SAL_MAX_UINT16
)
1984 xSupbook
= new XclExpSupbook( GetRoot() );
1985 mnAddInSB
= Append( xSupbook
);
1988 xSupbook
= maSupbookList
.GetRecord( mnAddInSB
);
1989 OSL_ENSURE( xSupbook
, "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
1990 rnSupbook
= mnAddInSB
;
1991 rnExtName
= xSupbook
->InsertAddIn( rName
);
1992 return rnExtName
> 0;
1995 bool XclExpSupbookBuffer::InsertEuroTool(
1996 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
, const OUString
& rName
)
1998 XclExpSupbookRef xSupbook
;
1999 OUString
aUrl( "\001\010EUROTOOL.XLA" );
2000 if( !GetSupbookUrl( xSupbook
, rnSupbook
, aUrl
) )
2002 xSupbook
= new XclExpSupbook( GetRoot(), aUrl
, XclSupbookType::Eurotool
);
2003 rnSupbook
= Append( xSupbook
);
2005 rnExtName
= xSupbook
->InsertEuroTool( rName
);
2006 return rnExtName
> 0;
2009 bool XclExpSupbookBuffer::InsertDde(
2010 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
,
2011 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
2013 XclExpSupbookRef xSupbook
;
2014 if( !GetSupbookDde( xSupbook
, rnSupbook
, rApplic
, rTopic
) )
2016 xSupbook
= new XclExpSupbook( GetRoot(), rApplic
, rTopic
);
2017 rnSupbook
= Append( xSupbook
);
2019 rnExtName
= xSupbook
->InsertDde( rItem
);
2020 return rnExtName
> 0;
2023 bool XclExpSupbookBuffer::InsertExtName(
2024 sal_uInt16
& rnSupbook
, sal_uInt16
& rnExtName
, const OUString
& rUrl
,
2025 const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
2027 XclExpSupbookRef xSupbook
;
2028 if (!GetSupbookUrl(xSupbook
, rnSupbook
, rUrl
))
2030 xSupbook
= new XclExpSupbook(GetRoot(), rUrl
);
2031 rnSupbook
= Append(xSupbook
);
2033 rnExtName
= xSupbook
->InsertExtName(rName
, rArray
);
2034 return rnExtName
> 0;
2037 XclExpXti
XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2038 XclExpRefLogEntry
* pRefLogEntry
)
2040 XclExpXti
aXti(0, EXC_NOTAB
, EXC_NOTAB
);
2041 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
2042 const OUString
* pUrl
= pRefMgr
->getExternalFileName(nFileId
);
2046 XclExpSupbookRef xSupbook
;
2047 sal_uInt16 nSupbookId
;
2048 if (!GetSupbookUrl(xSupbook
, nSupbookId
, *pUrl
))
2050 xSupbook
= new XclExpSupbook(GetRoot(), *pUrl
);
2051 nSupbookId
= Append(xSupbook
);
2053 aXti
.mnSupbook
= nSupbookId
;
2055 sal_uInt16 nFirstSheetId
= xSupbook
->GetTabIndex(rTabName
);
2056 if (nFirstSheetId
== EXC_NOTAB
)
2058 // first sheet not found in SUPBOOK.
2061 sal_uInt16 nSheetCount
= xSupbook
->GetTabCount();
2062 for (sal_uInt16 i
= 0; i
< nXclTabSpan
; ++i
)
2064 sal_uInt16 nSheetId
= nFirstSheetId
+ i
;
2065 if (nSheetId
>= nSheetCount
)
2068 FindSBIndexEntry
f(nSupbookId
, nSheetId
);
2069 if (::std::none_of(maSBIndexVec
.begin(), maSBIndexVec
.end(), f
))
2071 maSBIndexVec
.emplace_back();
2072 XclExpSBIndex
& r
= maSBIndexVec
.back();
2073 r
.mnSupbook
= nSupbookId
;
2074 r
.mnSBTab
= nSheetId
;
2077 aXti
.mnFirstSBTab
= nSheetId
;
2078 if (i
== nXclTabSpan
- 1)
2079 aXti
.mnLastSBTab
= nSheetId
;
2084 pRefLogEntry
->mnFirstXclTab
= 0;
2085 pRefLogEntry
->mnLastXclTab
= 0;
2087 xSupbook
->FillRefLogEntry(*pRefLogEntry
, aXti
.mnFirstSBTab
, aXti
.mnLastSBTab
);
2093 void XclExpSupbookBuffer::Save( XclExpStream
& rStrm
)
2095 maSupbookList
.Save( rStrm
);
2098 void XclExpSupbookBuffer::SaveXml( XclExpXmlStream
& rStrm
)
2100 // Unused external references are not saved, only kept in memory.
2101 // Those that are saved must be indexed from 1, so indexes must be reordered
2102 ScExternalRefManager
* pRefMgr
= GetDoc().GetExternalRefManager();
2103 vector
<sal_uInt16
> aExternFileIds
;
2104 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2106 XclExpSupbookRef
xRef(maSupbookList
.GetRecord(nPos
));
2107 // fileIDs are indexed from 1 in xlsx, and from 0 in ScExternalRefManager
2108 // converting between them require a -1 or +1
2109 if (xRef
->GetType() == XclSupbookType::Extern
)
2110 aExternFileIds
.push_back(xRef
->GetFileId() - 1);
2112 if (aExternFileIds
.size() > 0)
2113 pRefMgr
->setSkipUnusedFileIds(aExternFileIds
);
2115 ::std::map
< sal_uInt16
, OUString
> aMap
;
2116 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2118 XclExpSupbookRef
xRef( maSupbookList
.GetRecord( nPos
));
2119 if (xRef
->GetType() != XclSupbookType::Extern
)
2120 continue; // handle only external reference (for now?)
2122 sal_uInt16 nId
= xRef
->GetFileId();
2123 sal_uInt16 nUsedId
= pRefMgr
->convertFileIdToUsedFileId(nId
- 1) + 1;
2124 const OUString
& rUrl
= xRef
->GetUrl();
2125 ::std::pair
< ::std::map
< sal_uInt16
, OUString
>::iterator
, bool > aInsert(
2126 aMap
.insert( ::std::make_pair( nId
, rUrl
)));
2127 if (!aInsert
.second
)
2129 SAL_WARN( "sc.filter", "XclExpSupbookBuffer::SaveXml: file ID already used: " << nId
<<
2130 " wanted for " << rUrl
<< " and is " << (*aInsert
.first
).second
<<
2131 (rUrl
== (*aInsert
.first
).second
? " multiple Supbook not supported" : ""));
2135 sax_fastparser::FSHelperPtr pExternalLink
= rStrm
.CreateOutputStream(
2136 XclXmlUtils::GetStreamName( "xl/", "externalLinks/externalLink", nUsedId
),
2137 XclXmlUtils::GetStreamName( nullptr, "externalLinks/externalLink", nUsedId
),
2138 rStrm
.GetCurrentStream()->getOutputStream(),
2139 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
2140 CREATE_OFFICEDOC_RELATION_TYPE("externalLink"),
2143 // externalReference entry in workbook externalReferences
2144 rStrm
.GetCurrentStream()->singleElement( XML_externalReference
,
2145 FSNS(XML_r
, XML_id
), sId
.toUtf8() );
2147 // Each externalBook in a separate stream.
2148 rStrm
.PushStream( pExternalLink
);
2149 xRef
->SaveXml( rStrm
);
2154 bool XclExpSupbookBuffer::HasExternalReferences() const
2156 for (size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2158 if (maSupbookList
.GetRecord( nPos
)->GetType() == XclSupbookType::Extern
)
2164 bool XclExpSupbookBuffer::GetSupbookUrl(
2165 XclExpSupbookRef
& rxSupbook
, sal_uInt16
& rnIndex
, std::u16string_view rUrl
) const
2167 for( size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2169 rxSupbook
= maSupbookList
.GetRecord( nPos
);
2170 if( rxSupbook
->IsUrlLink( rUrl
) )
2172 rnIndex
= ulimit_cast
< sal_uInt16
>( nPos
);
2179 bool XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef
& rxSupbook
,
2180 sal_uInt16
& rnIndex
, std::u16string_view rApplic
, std::u16string_view rTopic
) const
2182 for( size_t nPos
= 0, nSize
= maSupbookList
.GetSize(); nPos
< nSize
; ++nPos
)
2184 rxSupbook
= maSupbookList
.GetRecord( nPos
);
2185 if( rxSupbook
->IsDdeLink( rApplic
, rTopic
) )
2187 rnIndex
= ulimit_cast
< sal_uInt16
>( nPos
);
2194 sal_uInt16
XclExpSupbookBuffer::Append( XclExpSupbookRef
const & xSupbook
)
2196 maSupbookList
.AppendRecord( xSupbook
);
2197 return ulimit_cast
< sal_uInt16
>( maSupbookList
.GetSize() - 1 );
2200 // Export link manager ========================================================
2202 XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot
& rRoot
) :
2207 XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot
& rRoot
) :
2208 XclExpLinkManagerImpl( rRoot
)
2212 void XclExpLinkManagerImpl5::FindExtSheet(
2213 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2214 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2216 FindInternal( rnExtSheet
, rnFirstXclTab
, nFirstScTab
);
2217 if( (rnFirstXclTab
== EXC_TAB_DELETED
) || (nFirstScTab
== nLastScTab
) )
2219 rnLastXclTab
= rnFirstXclTab
;
2223 sal_uInt16 nDummyExtSheet
;
2224 FindInternal( nDummyExtSheet
, rnLastXclTab
, nLastScTab
);
2227 OSL_ENSURE( !pRefLogEntry
, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
2230 sal_uInt16
XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode
)
2232 sal_uInt16 nExtSheet
;
2233 FindInternal( nExtSheet
, cCode
);
2237 void XclExpLinkManagerImpl5::FindExtSheet(
2238 sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, sal_uInt16
/*nXclTabSpan*/,
2239 sal_uInt16
& /*rnExtSheet*/, sal_uInt16
& /*rnFirstSBTab*/, sal_uInt16
& /*rnLastSBTab*/,
2240 XclExpRefLogEntry
* /*pRefLogEntry*/ )
2245 void XclExpLinkManagerImpl5::StoreCellRange( const ScSingleRefData
& /*rRef1*/, const ScSingleRefData
& /*rRef2*/, const ScAddress
& /*rPos*/ )
2250 void XclExpLinkManagerImpl5::StoreCell( sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, const ScAddress
& /*rPos*/ )
2255 void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16
/*nFileId*/, const OUString
& /*rTabName*/, const ScRange
& /*rRange*/ )
2260 bool XclExpLinkManagerImpl5::InsertAddIn(
2261 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rName
)
2263 XclExpExtSheetRef xExtSheet
= FindInternal( rnExtSheet
, EXC_EXTSH_ADDIN
);
2266 rnExtName
= xExtSheet
->InsertAddIn( rName
);
2267 return rnExtName
> 0;
2272 bool XclExpLinkManagerImpl5::InsertEuroTool(
2273 sal_uInt16
& /*rnExtSheet*/, sal_uInt16
& /*rnExtName*/, const OUString
& /*rName*/ )
2278 bool XclExpLinkManagerImpl5::InsertDde(
2279 sal_uInt16
& /*rnExtSheet*/, sal_uInt16
& /*rnExtName*/,
2280 const OUString
& /*rApplic*/, const OUString
& /*rTopic*/, const OUString
& /*rItem*/ )
2286 bool XclExpLinkManagerImpl5::InsertExtName(
2287 sal_uInt16
& /*rnExtSheet*/, sal_uInt16
& /*rnExtName*/, const OUString
& /*rUrl*/,
2288 const OUString
& /*rName*/, const ScExternalRefCache::TokenArrayRef
& /*rArray*/ )
2294 void XclExpLinkManagerImpl5::Save( XclExpStream
& rStrm
)
2296 if( sal_uInt16 nExtSheetCount
= GetExtSheetCount() )
2298 // EXTERNCOUNT record
2299 XclExpUInt16Record( EXC_ID_EXTERNCOUNT
, nExtSheetCount
).Save( rStrm
);
2300 // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
2301 maExtSheetList
.Save( rStrm
);
2305 void XclExpLinkManagerImpl5::SaveXml( XclExpXmlStream
& /*rStrm*/ )
2310 sal_uInt16
XclExpLinkManagerImpl5::GetExtSheetCount() const
2312 return static_cast< sal_uInt16
>( maExtSheetList
.GetSize() );
2315 sal_uInt16
XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef
const & xExtSheet
)
2317 if( GetExtSheetCount() < 0x7FFF )
2319 maExtSheetList
.AppendRecord( xExtSheet
);
2320 // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
2321 return static_cast< sal_uInt16
>( -GetExtSheetCount() );
2326 void XclExpLinkManagerImpl5::CreateInternal()
2328 if( !maIntTabMap
.empty() )
2331 // create EXTERNSHEET records for all internal exported sheets
2332 XclExpTabInfo
& rTabInfo
= GetTabInfo();
2333 for( SCTAB nScTab
= 0, nScCnt
= rTabInfo
.GetScTabCount(); nScTab
< nScCnt
; ++nScTab
)
2335 if( rTabInfo
.IsExportTab( nScTab
) )
2337 XclExpExtSheetRef xRec
;
2338 if( nScTab
== GetCurrScTab() )
2339 xRec
= new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB
);
2341 xRec
= new XclExpExternSheet( GetRoot(), rTabInfo
.GetScTabName( nScTab
) );
2342 maIntTabMap
[ nScTab
] = AppendInternal( xRec
);
2347 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet
)
2349 return maExtSheetList
.GetRecord( static_cast< sal_uInt16
>( -nExtSheet
- 1 ) );
2352 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::FindInternal(
2353 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
, SCTAB nScTab
)
2355 // create internal EXTERNSHEET records on demand
2358 // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
2359 XclExpExtSheetRef xExtSheet
;
2360 XclExpIntTabMap::const_iterator aIt
= maIntTabMap
.find( nScTab
);
2361 if( aIt
== maIntTabMap
.end() )
2363 xExtSheet
= FindInternal( rnExtSheet
, EXC_EXTSH_OWNDOC
);
2364 rnXclTab
= EXC_TAB_DELETED
;
2368 rnExtSheet
= aIt
->second
;
2369 xExtSheet
= GetInternal( rnExtSheet
);
2370 rnXclTab
= GetTabInfo().GetXclTab( nScTab
);
2375 XclExpLinkManagerImpl5::XclExpExtSheetRef
XclExpLinkManagerImpl5::FindInternal(
2376 sal_uInt16
& rnExtSheet
, sal_Unicode cCode
)
2378 XclExpExtSheetRef xExtSheet
;
2379 XclExpCodeMap::const_iterator aIt
= maCodeMap
.find( cCode
);
2380 if( aIt
== maCodeMap
.end() )
2382 xExtSheet
= new XclExpExternSheet( GetRoot(), cCode
);
2383 rnExtSheet
= maCodeMap
[ cCode
] = AppendInternal( xExtSheet
);
2387 rnExtSheet
= aIt
->second
;
2388 xExtSheet
= GetInternal( rnExtSheet
);
2393 XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot
& rRoot
) :
2394 XclExpLinkManagerImpl( rRoot
),
2399 void XclExpLinkManagerImpl8::FindExtSheet(
2400 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2401 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2403 XclExpTabInfo
& rTabInfo
= GetTabInfo();
2404 rnFirstXclTab
= rTabInfo
.GetXclTab( nFirstScTab
);
2405 rnLastXclTab
= rTabInfo
.GetXclTab( nLastScTab
);
2406 rnExtSheet
= InsertXti( maSBBuffer
.GetXti( rnFirstXclTab
, rnLastXclTab
, pRefLogEntry
) );
2409 sal_uInt16
XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode
)
2411 OSL_ENSURE( (cCode
== EXC_EXTSH_OWNDOC
) || (cCode
== EXC_EXTSH_ADDIN
),
2412 "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
2413 return InsertXti( maSBBuffer
.GetXti( EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2416 void XclExpLinkManagerImpl8::FindExtSheet(
2417 sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2418 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
2419 XclExpRefLogEntry
* pRefLogEntry
)
2421 XclExpXti aXti
= maSBBuffer
.GetXti(nFileId
, rTabName
, nXclTabSpan
, pRefLogEntry
);
2422 rnExtSheet
= InsertXti(aXti
);
2423 rnFirstSBTab
= aXti
.mnFirstSBTab
;
2424 rnLastSBTab
= aXti
.mnLastSBTab
;
2427 void XclExpLinkManagerImpl8::StoreCellRange( const ScSingleRefData
& rRef1
, const ScSingleRefData
& rRef2
, const ScAddress
& rPos
)
2429 ScAddress aAbs1
= rRef1
.toAbs(GetRoot().GetDoc(), rPos
);
2430 ScAddress aAbs2
= rRef2
.toAbs(GetRoot().GetDoc(), rPos
);
2431 if (!(!rRef1
.IsDeleted() && !rRef2
.IsDeleted() && (aAbs1
.Tab() >= 0) && (aAbs2
.Tab() >= 0)))
2434 const XclExpTabInfo
& rTabInfo
= GetTabInfo();
2435 SCTAB nFirstScTab
= aAbs1
.Tab();
2436 SCTAB nLastScTab
= aAbs2
.Tab();
2437 ScRange
aRange(aAbs1
.Col(), aAbs1
.Row(), 0, aAbs2
.Col(), aAbs2
.Row(), 0);
2438 for (SCTAB nScTab
= nFirstScTab
; nScTab
<= nLastScTab
; ++nScTab
)
2440 if( rTabInfo
.IsExternalTab( nScTab
) )
2442 aRange
.aStart
.SetTab( nScTab
);
2443 aRange
.aEnd
.SetTab( nScTab
);
2444 maSBBuffer
.StoreCellRange( aRange
);
2449 void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
)
2451 maSBBuffer
.StoreCell(nFileId
, rTabName
, rPos
);
2454 void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
2456 maSBBuffer
.StoreCellRange(nFileId
, rTabName
, rRange
);
2459 bool XclExpLinkManagerImpl8::InsertAddIn(
2460 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rName
)
2462 sal_uInt16 nSupbook
;
2463 if( maSBBuffer
.InsertAddIn( nSupbook
, rnExtName
, rName
) )
2465 rnExtSheet
= InsertXti( XclExpXti( nSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2471 bool XclExpLinkManagerImpl8::InsertEuroTool(
2472 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rName
)
2474 sal_uInt16 nSupbook
;
2475 if( maSBBuffer
.InsertEuroTool( nSupbook
, rnExtName
, rName
) )
2477 rnExtSheet
= InsertXti( XclExpXti( nSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2483 bool XclExpLinkManagerImpl8::InsertDde(
2484 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
2485 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
2487 sal_uInt16 nSupbook
;
2488 if( maSBBuffer
.InsertDde( nSupbook
, rnExtName
, rApplic
, rTopic
, rItem
) )
2490 rnExtSheet
= InsertXti( XclExpXti( nSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2496 bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
2497 const OUString
& rUrl
, const OUString
& rName
, const ScExternalRefCache::TokenArrayRef
& rArray
)
2499 sal_uInt16 nSupbook
;
2500 if( maSBBuffer
.InsertExtName( nSupbook
, rnExtName
, rUrl
, rName
, rArray
) )
2502 rnExtSheet
= InsertXti( XclExpXti( nSupbook
, EXC_TAB_EXTERNAL
, EXC_TAB_EXTERNAL
) );
2508 void XclExpLinkManagerImpl8::Save( XclExpStream
& rStrm
)
2510 if( maXtiVec
.empty() )
2513 // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
2514 maSBBuffer
.Save( rStrm
);
2517 sal_uInt16 nCount
= ulimit_cast
< sal_uInt16
>( maXtiVec
.size() );
2518 rStrm
.StartRecord( EXC_ID_EXTERNSHEET
, 2 + 6 * nCount
);
2520 rStrm
.SetSliceSize( 6 );
2521 for( const auto& rXti
: maXtiVec
)
2526 void XclExpLinkManagerImpl8::SaveXml( XclExpXmlStream
& rStrm
)
2528 if (maSBBuffer
.HasExternalReferences())
2530 sax_fastparser::FSHelperPtr pWorkbook
= rStrm
.GetCurrentStream();
2531 pWorkbook
->startElement(XML_externalReferences
);
2533 // externalLink, externalBook, sheetNames, sheetDataSet, externalName
2534 maSBBuffer
.SaveXml( rStrm
);
2536 pWorkbook
->endElement( XML_externalReferences
);
2539 // TODO: equivalent for EXTERNSHEET in OOXML?
2541 if( !maXtiVec
.empty() )
2543 for( const auto& rXti
: maXtiVec
)
2544 rXti
.SaveXml( rStrm
);
2549 sal_uInt16
XclExpLinkManagerImpl8::InsertXti( const XclExpXti
& rXti
)
2551 auto aIt
= std::find(maXtiVec
.begin(), maXtiVec
.end(), rXti
);
2552 if (aIt
!= maXtiVec
.end())
2553 return ulimit_cast
< sal_uInt16
>( std::distance(maXtiVec
.begin(), aIt
) );
2554 maXtiVec
.push_back( rXti
);
2555 return ulimit_cast
< sal_uInt16
>( maXtiVec
.size() - 1 );
2558 XclExpLinkManager::XclExpLinkManager( const XclExpRoot
& rRoot
) :
2564 mxImpl
= std::make_shared
<XclExpLinkManagerImpl5
>( rRoot
);
2567 mxImpl
= std::make_shared
<XclExpLinkManagerImpl8
>( rRoot
);
2574 XclExpLinkManager::~XclExpLinkManager()
2578 void XclExpLinkManager::FindExtSheet(
2579 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnXclTab
,
2580 SCTAB nScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2582 mxImpl
->FindExtSheet( rnExtSheet
, rnXclTab
, rnXclTab
, nScTab
, nScTab
, pRefLogEntry
);
2585 void XclExpLinkManager::FindExtSheet(
2586 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstXclTab
, sal_uInt16
& rnLastXclTab
,
2587 SCTAB nFirstScTab
, SCTAB nLastScTab
, XclExpRefLogEntry
* pRefLogEntry
)
2589 mxImpl
->FindExtSheet( rnExtSheet
, rnFirstXclTab
, rnLastXclTab
, nFirstScTab
, nLastScTab
, pRefLogEntry
);
2592 sal_uInt16
XclExpLinkManager::FindExtSheet( sal_Unicode cCode
)
2594 return mxImpl
->FindExtSheet( cCode
);
2597 void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId
, const OUString
& rTabName
, sal_uInt16 nXclTabSpan
,
2598 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnFirstSBTab
, sal_uInt16
& rnLastSBTab
,
2599 XclExpRefLogEntry
* pRefLogEntry
)
2601 mxImpl
->FindExtSheet( nFileId
, rTabName
, nXclTabSpan
, rnExtSheet
, rnFirstSBTab
, rnLastSBTab
, pRefLogEntry
);
2604 void XclExpLinkManager::StoreCell( const ScSingleRefData
& rRef
, const ScAddress
& rPos
)
2606 mxImpl
->StoreCellRange(rRef
, rRef
, rPos
);
2609 void XclExpLinkManager::StoreCellRange( const ScComplexRefData
& rRef
, const ScAddress
& rPos
)
2611 mxImpl
->StoreCellRange(rRef
.Ref1
, rRef
.Ref2
, rPos
);
2614 void XclExpLinkManager::StoreCell( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScAddress
& rPos
)
2616 mxImpl
->StoreCell(nFileId
, rTabName
, rPos
);
2619 void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScRange
& rRange
)
2621 mxImpl
->StoreCellRange(nFileId
, rTabName
, rRange
);
2624 bool XclExpLinkManager::InsertAddIn(
2625 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rName
)
2627 return mxImpl
->InsertAddIn( rnExtSheet
, rnExtName
, rName
);
2630 bool XclExpLinkManager::InsertEuroTool(
2631 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rName
)
2633 return mxImpl
->InsertEuroTool( rnExtSheet
, rnExtName
, rName
);
2636 bool XclExpLinkManager::InsertDde(
2637 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
,
2638 const OUString
& rApplic
, const OUString
& rTopic
, const OUString
& rItem
)
2640 return mxImpl
->InsertDde( rnExtSheet
, rnExtName
, rApplic
, rTopic
, rItem
);
2643 bool XclExpLinkManager::InsertExtName(
2644 sal_uInt16
& rnExtSheet
, sal_uInt16
& rnExtName
, const OUString
& rUrl
, const OUString
& rName
,
2645 const ScExternalRefCache::TokenArrayRef
& rArray
)
2647 return mxImpl
->InsertExtName(rnExtSheet
, rnExtName
, rUrl
, rName
, rArray
);
2650 void XclExpLinkManager::Save( XclExpStream
& rStrm
)
2652 mxImpl
->Save( rStrm
);
2655 void XclExpLinkManager::SaveXml( XclExpXmlStream
& rStrm
)
2657 mxImpl
->SaveXml( rStrm
);
2660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */