1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <xelink.hxx>
21 
22 #include <algorithm>
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/zforlist.hxx>
28 #include <sal/log.hxx>
29 #include <document.hxx>
30 #include <scextopt.hxx>
31 #include <externalrefmgr.hxx>
32 #include <tokenarray.hxx>
33 #include <xecontent.hxx>
34 #include <xeformula.hxx>
35 #include <xehelper.hxx>
36 #include <xllink.hxx>
37 #include <xltools.hxx>
38 
39 #include <vector>
40 #include <memory>
41 
42 using ::std::unique_ptr;
43 using ::std::vector;
44 using ::com::sun::star::uno::Any;
45 
46 using namespace oox;
47 
48 // *** Helper classes ***
49 
50 // External names =============================================================
51 
52 /** This is a base class for any external name (i.e. add-in names or DDE links).
53     @descr  Derived classes implement creation and export of the external names. */
54 class XclExpExtNameBase : public XclExpRecord, protected XclExpRoot
55 {
56 public:
57     /** @param nFlags  The flags to export. */
58     explicit            XclExpExtNameBase( const XclExpRoot& rRoot,
59                             const OUString& rName, sal_uInt16 nFlags = 0 );
60 
61     /** Returns the name string of the external name. */
GetName() const62     const OUString& GetName() const { return maName; }
63 
64 private:
65     /** Writes the start of the record that is equal in all EXTERNNAME records and calls WriteAddData(). */
66     virtual void        WriteBody( XclExpStream& rStrm ) override;
67     /** Called to write additional data following the common record contents.
68         @descr  Derived classes should overwrite this function to write their data. */
69     virtual void        WriteAddData( XclExpStream& rStrm );
70 
71 protected:
72     OUString            maName;         /// Calc name (title) of the external name.
73     XclExpStringRef     mxName;         /// Excel name (title) of the external name.
74     sal_uInt16          mnFlags;        /// Flags for record export.
75 };
76 
77 /** Represents an EXTERNNAME record for an add-in function name. */
78 class XclExpExtNameAddIn : public XclExpExtNameBase
79 {
80 public:
81     explicit            XclExpExtNameAddIn( const XclExpRoot& rRoot, const OUString& rName );
82 
83 private:
84     /** Writes additional record contents. */
85     virtual void        WriteAddData( XclExpStream& rStrm ) override;
86 };
87 
88 /** Represents an EXTERNNAME record for a DDE link. */
89 class XclExpExtNameDde : public XclExpExtNameBase
90 {
91 public:
92     explicit            XclExpExtNameDde( const XclExpRoot& rRoot, const OUString& rName,
93                             sal_uInt16 nFlags, const ScMatrix* pResults = nullptr );
94 
95 private:
96     /** Writes additional record contents. */
97     virtual void        WriteAddData( XclExpStream& rStrm ) override;
98 
99 private:
100     typedef std::shared_ptr< XclExpCachedMatrix > XclExpCachedMatRef;
101     XclExpCachedMatRef  mxMatrix;       /// Cached results of the DDE link.
102 };
103 
104 class XclExpSupbook;
105 
106 class XclExpExtName : public XclExpExtNameBase
107 {
108 public:
109     explicit            XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const OUString& rName,
110                                        const ScExternalRefCache::TokenArrayRef& rArray );
111 
112     virtual void SaveXml(XclExpXmlStream& rStrm) override;
113 
114 private:
115     /** Writes additional record contents. */
116     virtual void        WriteAddData( XclExpStream& rStrm ) override;
117 
118 private:
119     const XclExpSupbook&    mrSupbook;
120     unique_ptr<ScTokenArray>  mpArray;
121 };
122 
123 // List of external names =====================================================
124 
125 /** List of all external names of a sheet. */
126 class XclExpExtNameBuffer : public XclExpRecordBase, protected XclExpRoot
127 {
128 public:
129     explicit            XclExpExtNameBuffer( const XclExpRoot& rRoot );
130 
131     /** Inserts an add-in function name
132         @return  The 1-based (Excel-like) list index of the name. */
133     sal_uInt16          InsertAddIn( const OUString& rName );
134     /** InsertEuroTool */
135     sal_uInt16          InsertEuroTool( const OUString& rName );
136     /** Inserts a DDE link.
137         @return  The 1-based (Excel-like) list index of the DDE link. */
138     sal_uInt16          InsertDde( const OUString& rApplic, const OUString& rTopic, const OUString& rItem );
139 
140     sal_uInt16          InsertExtName( const XclExpSupbook& rSupbook, const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray );
141 
142     /** Writes the EXTERNNAME record list. */
143     virtual void        Save( XclExpStream& rStrm ) override;
144 
145     virtual void SaveXml(XclExpXmlStream& rStrm) override;
146 
147 private:
148     typedef XclExpRecordList< XclExpExtNameBase >   XclExpExtNameList;
149     typedef XclExpExtNameList::RecordRefType        XclExpExtNameRef;
150 
151 private:
152     /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
153     sal_uInt16          GetIndex( const OUString& 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 );
157 
158 private:
159     XclExpExtNameList   maNameList;     /// The list with all EXTERNNAME records.
160 };
161 
162 // Cached external cells ======================================================
163 
164 /** Stores the contents of a consecutive row of external cells (record CRN). */
165 class XclExpCrn : public XclExpRecord
166 {
167 public:
168     explicit            XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue );
169 
170     /** Returns true, if the passed value could be appended to this record. */
171     bool                InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
172 
173     /** Writes the row and child elements. */
174     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
175 
176 private:
177     virtual void        WriteBody( XclExpStream& rStrm ) override;
178 
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 );
184 
185 private:
186     typedef ::std::vector< Any > CachedValues;
187 
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.
191 };
192 
193 namespace { class XclExpCrnList; }
194 
195 /** Represents the record XCT which is the header record of a CRN record list.
196  */
197 class XclExpXct : public XclExpRecordBase, protected XclExpRoot
198 {
199 public:
200     explicit            XclExpXct( const XclExpRoot& rRoot,
201                             const OUString& rTabName, sal_uInt16 nSBTab,
202                             ScExternalRefCache::TableTypeRef const & xCacheTable );
203 
204     /** Returns the external sheet name. */
GetTabName() const205     const XclExpString& GetTabName() const { return maTabName; }
206 
207     /** Stores all cells in the given range in the CRN list. */
208     void                StoreCellRange( const ScRange& rRange );
209 
210     void                StoreCell_( const ScAddress& rCell );
211     void                StoreCellRange_( const ScRange& rRange );
212 
213     /** Writes the XCT and all CRN records. */
214     virtual void        Save( XclExpStream& rStrm ) override;
215 
216     /** Writes the sheetDataSet and child elements. */
217     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
218 
219 private:
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.
225 
226     /** Build the internal representation of records to be saved as BIFF or OOXML. */
227     bool                BuildCrnList( XclExpCrnList& rCrnRecs );
228 };
229 
230 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
231 
232 /** Base class for records representing external sheets/documents.
233 
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
237     sheets.
238  */
239 class XclExpExternSheetBase : public XclExpRecord, protected XclExpRoot
240 {
241 public:
242     explicit            XclExpExternSheetBase( const XclExpRoot& rRoot,
243                             sal_uInt16 nRecId, sal_uInt32 nRecSize = 0 );
244 
245 protected:
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 );
252 
253 protected:
254     typedef std::shared_ptr< XclExpExtNameBuffer >   XclExpExtNameBfrRef;
255     XclExpExtNameBfrRef mxExtNameBfr;   /// List of EXTERNNAME records.
256 };
257 
258 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
259 
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
264 {
265 public:
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, const OUString& rTabName );
270 
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 );
274 
275     /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
276     virtual void        Save( XclExpStream& rStrm ) override;
277 
278 private:
279     /** Initializes the record data with the passed encoded URL. */
280     void                Init( const OUString& rEncUrl );
281     /** Writes the contents of the EXTERNSHEET  record. */
282     virtual void        WriteBody( XclExpStream& rStrm ) override;
283 
284 private:
285     XclExpString        maTabName;      /// The name of the sheet.
286 };
287 
288 // External documents (SUPBOOK, BIFF8) ========================================
289 
290 /** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
291 class XclExpSupbook : public XclExpExternSheetBase
292 {
293 public:
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 );
304 
305     /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
306     bool                IsUrlLink( const OUString& rUrl ) const;
307     /** Returns true, if this SUPBOOK contains the passed DDE link. */
308     bool                IsDdeLink( const OUString& rApplic, const OUString& 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;
312 
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 );
315 
316     void                StoreCell_( sal_uInt16 nSBTab, const ScAddress& rCell );
317     void                StoreCellRange_( sal_uInt16 nSBTab, const ScRange& rRange );
318 
319     sal_uInt16          GetTabIndex( const OUString& rTabName ) const;
320     sal_uInt16          GetTabCount() const;
321 
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 );
332 
333     sal_uInt16          InsertExtName( const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray );
334 
335     /** Get the type of record. */
336     XclSupbookType      GetType() const;
337 
338     /** For references to an external document, 1-based OOXML file ID. */
339     sal_uInt16          GetFileId() const;
340 
341     /** For references to an external document. */
342     const OUString&     GetUrl() const;
343 
344     /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
345     virtual void        Save( XclExpStream& rStrm ) override;
346 
347     /** Writes the externalBook and all child elements. */
348     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
349 
350 private:
351     /** Returns the sheet name inside of this SUPBOOK. */
352     const XclExpString* GetTabName( sal_uInt16 nSBTab ) const;
353 
354     /** Writes the SUPBOOK record contents. */
355     virtual void        WriteBody( XclExpStream& rStrm ) override;
356 
357 private:
358     typedef XclExpRecordList< XclExpXct >   XclExpXctList;
359     typedef XclExpXctList::RecordRefType    XclExpXctRef;
360 
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
368 };
369 
370 // All SUPBOOKS in a document =================================================
371 
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. */
375 struct XclExpXti
376 {
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.
380 
XclExpXtiXclExpXti381     explicit     XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
XclExpXtiXclExpXti382     explicit     XclExpXti( sal_uInt16 nSupbook, sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) :
383                             mnSupbook( nSupbook ), mnFirstSBTab( nFirstSBTab ), mnLastSBTab( nLastSBTab ) {}
384 
385     /** Writes this XTI structure (inside of the EXTERNSHEET record). */
SaveXclExpXti386     void         Save( XclExpStream& rStrm ) const
387                             { rStrm << mnSupbook << mnFirstSBTab << mnLastSBTab; }
388 };
389 
operator ==(const XclExpXti & rLeft,const XclExpXti & rRight)390 static bool operator==( const XclExpXti& rLeft, const XclExpXti& rRight )
391 {
392     return
393         (rLeft.mnSupbook    == rRight.mnSupbook)    &&
394         (rLeft.mnFirstSBTab == rRight.mnFirstSBTab) &&
395         (rLeft.mnLastSBTab  == rRight.mnLastSBTab);
396 }
397 
398 /** Contains a list of all SUPBOOK records and index arrays of external sheets. */
399 class XclExpSupbookBuffer : public XclExpRecordBase, protected XclExpRoot
400 {
401 public:
402     explicit            XclExpSupbookBuffer( const XclExpRoot& rRoot );
403 
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;
408 
409     /** Stores all cells in the given range in a CRN record list. */
410     void                StoreCellRange( const ScRange& rRange );
411 
412     void                StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell );
413     void                StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange );
414 
415     /** Finds or inserts an EXTERNNAME record for an add-in function name.
416         @param rnSupbook  Returns the index of the SUPBOOK record which contains the add-in function name.
417         @param rnExtName  Returns the 1-based EXTERNNAME record index. */
418     bool                InsertAddIn(
419                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
420                             const OUString& rName );
421     /** InsertEuroTool */
422     bool                InsertEuroTool(
423                              sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
424                              const OUString& rName );
425     /** Finds or inserts an EXTERNNAME record for DDE links.
426         @param rnSupbook  Returns the index of the SUPBOOK record which contains the DDE link.
427         @param rnExtName  Returns the 1-based EXTERNNAME record index. */
428     bool                InsertDde(
429                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
430                             const OUString& rApplic, const OUString& rTopic, const OUString& rItem );
431 
432     bool                InsertExtName(
433                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const OUString& rUrl,
434                             const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray );
435 
436     XclExpXti           GetXti( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
437                                 XclExpRefLogEntry* pRefLogEntry );
438 
439     /** Writes all SUPBOOK records with their sub records. */
440     virtual void        Save( XclExpStream& rStrm ) override;
441 
442     /** Writes all externalBook elements with their child elements to OOXML. */
443     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
444 
445     /** Whether we need to write externalReferences or not. */
446     bool                HasExternalReferences() const;
447 
448     struct XclExpSBIndex
449     {
450         sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
451         sal_uInt16          mnSBTab;            /// Sheet name index in SUPBOOK for an Excel sheet.
SetXclExpSupbookBuffer::XclExpSBIndex452         void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
453                                 { mnSupbook = nSupbook; mnSBTab = nSBTab; }
454     };
455     typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
456 
457 private:
458     typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
459     typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
460 
461 private:
462     /** Searches for the SUPBOOK record containing the passed document URL.
463         @param rxSupbook  (out-param) Returns a reference to the SUPBOOK record, or 0.
464         @param rnIndex  (out-param) Returns the list index, if the SUPBOOK exists.
465         @return  True, if the SUPBOOK record exists (out-parameters are valid). */
466     bool                GetSupbookUrl( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
467                             const OUString& rUrl ) const;
468     /** Searches for the SUPBOOK record containing the passed DDE link.
469         @param rxSupbook  (out-param) Returns a reference to the SUPBOOK record, or 0.
470         @param rnIndex  (out-param) Returns the list index, if the SUPBOOK exists.
471         @return  True, if the SUPBOOK record exists (out-parameters are valid). */
472     bool                GetSupbookDde( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
473                             const OUString& rApplic, const OUString& rTopic ) const;
474 
475     /** Appends a new SUPBOOK to the list.
476         @return  The list index of the SUPBOOK record. */
477     sal_uInt16          Append( XclExpSupbookRef const & xSupbook );
478 
479 private:
480     XclExpSupbookList   maSupbookList;      /// List of all SUPBOOK records.
481     XclExpSBIndexVec    maSBIndexVec;       /// SUPBOOK and sheet name index for each Excel sheet.
482     sal_uInt16          mnOwnDocSB;         /// Index to SUPBOOK for own document.
483     sal_uInt16          mnAddInSB;          /// Index to add-in SUPBOOK.
484 };
485 
486 // Export link manager ========================================================
487 
488 /** Abstract base class for implementation classes of the link manager. */
489 class XclExpLinkManagerImpl : protected XclExpRoot
490 {
491 public:
492     /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
493     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
494                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
495                             SCTAB nFirstScTab, SCTAB nLastScTab,
496                             XclExpRefLogEntry* pRefLogEntry ) = 0;
497     /** Derived classes search for a special EXTERNSHEET index for the own document. */
498     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) = 0;
499 
500     virtual void FindExtSheet( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
501                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
502                                XclExpRefLogEntry* pRefLogEntry ) = 0;
503 
504     /** Derived classes store all cells in the given range in a CRN record list. */
505     virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2, const ScAddress& rPos ) = 0;
506 
507     virtual void StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rPos ) = 0;
508     virtual void StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange ) = 0;
509 
510     /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
511     virtual bool        InsertAddIn(
512                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
513                             const OUString& rName ) = 0;
514     /** InsertEuroTool */
515     virtual bool        InsertEuroTool(
516                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
517                             const OUString& rName ) = 0;
518 
519     /** Derived classes find or insert an EXTERNNAME record for DDE links. */
520     virtual bool        InsertDde(
521                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
522                             const OUString& rApplic, const OUString& rTopic, const OUString& rItem ) = 0;
523 
524     virtual bool        InsertExtName(
525                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rUrl,
526                             const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray ) = 0;
527 
528     /** Derived classes write the entire link table to the passed stream. */
529     virtual void        Save( XclExpStream& rStrm ) = 0;
530 
531     /** Derived classes write the entire link table to the passed OOXML stream. */
532     virtual void        SaveXml( XclExpXmlStream& rStrm ) = 0;
533 
534 protected:
535     explicit            XclExpLinkManagerImpl( const XclExpRoot& rRoot );
536 };
537 
538 /** Implementation of the link manager for BIFF5/BIFF7. */
539 class XclExpLinkManagerImpl5 : public XclExpLinkManagerImpl
540 {
541 public:
542     explicit            XclExpLinkManagerImpl5( const XclExpRoot& rRoot );
543 
544     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
545                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
546                             SCTAB nFirstScTab, SCTAB nLastScTab,
547                             XclExpRefLogEntry* pRefLogEntry ) override;
548     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) override;
549 
550     virtual void FindExtSheet( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
551                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
552                                XclExpRefLogEntry* pRefLogEntry ) override;
553 
554     virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2, const ScAddress& rPos ) override;
555 
556     virtual void StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rPos ) override;
557     virtual void StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange ) override;
558 
559     virtual bool        InsertAddIn(
560                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
561                             const OUString& rName ) override;
562 
563     /** InsertEuroTool */
564     virtual bool        InsertEuroTool(
565                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
566                              const OUString& rName ) override;
567 
568     virtual bool        InsertDde(
569                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
570                             const OUString& rApplic, const OUString& rTopic, const OUString& rItem ) override;
571 
572     virtual bool        InsertExtName(
573                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rUrl,
574                             const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray ) override;
575 
576     virtual void        Save( XclExpStream& rStrm ) override;
577 
578     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
579 
580 private:
581     typedef XclExpRecordList< XclExpExternSheet >   XclExpExtSheetList;
582     typedef XclExpExtSheetList::RecordRefType       XclExpExtSheetRef;
583     typedef ::std::map< SCTAB, sal_uInt16 >         XclExpIntTabMap;
584     typedef ::std::map< sal_Unicode, sal_uInt16 >   XclExpCodeMap;
585 
586 private:
587     /** Returns the number of EXTERNSHEET records. */
588     sal_uInt16          GetExtSheetCount() const;
589 
590     /** Appends an internal EXTERNSHEET record and returns the one-based index. */
591     sal_uInt16          AppendInternal( XclExpExtSheetRef const & xExtSheet );
592     /** Creates all EXTERNSHEET records for internal sheets on first call. */
593     void                CreateInternal();
594 
595     /** Returns the specified internal EXTERNSHEET record. */
596     XclExpExtSheetRef   GetInternal( sal_uInt16 nExtSheet );
597     /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
598     XclExpExtSheetRef   FindInternal( sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab );
599     /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
600     XclExpExtSheetRef   FindInternal( sal_uInt16& rnExtSheet, sal_Unicode cCode );
601 
602 private:
603     XclExpExtSheetList  maExtSheetList;     /// List with EXTERNSHEET records.
604     XclExpIntTabMap     maIntTabMap;        /// Maps internal Calc sheets to EXTERNSHEET records.
605     XclExpCodeMap       maCodeMap;          /// Maps special external codes to EXTERNSHEET records.
606 };
607 
608 /** Implementation of the link manager for BIFF8 and OOXML. */
609 class XclExpLinkManagerImpl8 : public XclExpLinkManagerImpl
610 {
611 public:
612     explicit            XclExpLinkManagerImpl8( const XclExpRoot& rRoot );
613 
614     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
615                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
616                             SCTAB nFirstScTab, SCTAB nLastScTab,
617                             XclExpRefLogEntry* pRefLogEntry ) override;
618     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) override;
619 
620     virtual void FindExtSheet( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
621                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
622                                XclExpRefLogEntry* pRefLogEntry ) override;
623 
624     virtual void StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2, const ScAddress& rPos ) override;
625 
626     virtual void StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rPos ) override;
627     virtual void StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange ) override;
628 
629     virtual bool        InsertAddIn(
630                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
631                             const OUString& rName ) override;
632     /** InsertEuroTool */
633     virtual bool        InsertEuroTool(
634                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
635                             const OUString& rName ) override;
636 
637     virtual bool        InsertDde(
638                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
639                             const OUString& rApplic, const OUString& rTopic, const OUString& rItem ) override;
640 
641     virtual bool        InsertExtName(
642                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rUrl,
643                             const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray ) override;
644 
645     virtual void        Save( XclExpStream& rStrm ) override;
646 
647     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
648 
649 private:
650     /** Searches for or inserts a new XTI structure.
651         @return  The 0-based list index of the XTI structure. */
652     sal_uInt16          InsertXti( const XclExpXti& rXti );
653 
654 private:
655     typedef ::std::vector< XclExpXti > XclExpXtiVec;
656 
657     XclExpSupbookBuffer maSBBuffer;     /// List of all SUPBOOK records.
658     XclExpXtiVec        maXtiVec;       /// List of XTI structures for the EXTERNSHEET record.
659 };
660 
661 // *** Implementation ***
662 
663 // Excel sheet indexes ========================================================
664 
665 
XclExpTabInfo(const XclExpRoot & rRoot)666 XclExpTabInfo::XclExpTabInfo( const XclExpRoot& rRoot ) :
667     XclExpRoot( rRoot ),
668     mnScCnt( 0 ),
669     mnXclCnt( 0 ),
670     mnXclExtCnt( 0 ),
671     mnXclSelCnt( 0 ),
672     mnDisplXclTab( 0 ),
673     mnFirstVisXclTab( 0 )
674 {
675     ScDocument& rDoc = GetDoc();
676     ScExtDocOptions& rDocOpt = GetExtDocOptions();
677 
678     mnScCnt = rDoc.GetTableCount();
679 
680     SCTAB nScTab;
681     SCTAB nFirstVisScTab = SCTAB_INVALID;   // first visible sheet
682     SCTAB nFirstExpScTab = SCTAB_INVALID;   // first exported sheet
683 
684     // --- initialize the flags in the index buffer ---
685 
686     maTabInfoVec.resize( mnScCnt );
687     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
688     {
689         // ignored sheets (skipped by export, with invalid Excel sheet index)
690         if( rDoc.IsScenario( nScTab ) )
691         {
692             SetFlag( nScTab, ExcTabBufFlags::Ignore );
693         }
694 
695         // external sheets (skipped, but with valid Excel sheet index for ref's)
696         else if( rDoc.GetLinkMode( nScTab ) == ScLinkMode::VALUE )
697         {
698             SetFlag( nScTab, ExcTabBufFlags::Extern );
699         }
700 
701         // exported sheets
702         else
703         {
704             // sheet name
705             rDoc.GetName( nScTab, maTabInfoVec[ nScTab ].maScName );
706 
707             // remember first exported sheet
708             if( nFirstExpScTab == SCTAB_INVALID )
709                nFirstExpScTab = nScTab;
710             // remember first visible exported sheet
711             if( (nFirstVisScTab == SCTAB_INVALID) && rDoc.IsVisible( nScTab ) )
712                nFirstVisScTab = nScTab;
713 
714             // sheet visible (only exported sheets)
715             SetFlag( nScTab, ExcTabBufFlags::Visible, rDoc.IsVisible( nScTab ) );
716 
717             // sheet selected (only exported sheets)
718             if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nScTab ) )
719                 SetFlag( nScTab, ExcTabBufFlags::Selected, pTabSett->mbSelected );
720 
721             // sheet mirrored (only exported sheets)
722             SetFlag( nScTab, ExcTabBufFlags::Mirrored, rDoc.IsLayoutRTL( nScTab ) );
723         }
724     }
725 
726     // --- visible/selected sheets ---
727 
728     SCTAB nDisplScTab = rDocOpt.GetDocSettings().mnDisplTab;
729 
730     // missing viewdata at embedded XLSX OLE objects
731     if (nDisplScTab == -1 )
732         nDisplScTab = rDoc.GetVisibleTab();
733 
734     // find first visible exported sheet
735     if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
736     {
737         // no exportable visible sheet -> use first exportable sheet
738         nFirstVisScTab = nFirstExpScTab;
739         if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
740         {
741             // no exportable sheet at all -> use active sheet and export it
742             nFirstVisScTab = nDisplScTab;
743             SetFlag( nFirstVisScTab, ExcTabBufFlags::SkipMask, false ); // clear skip flags
744         }
745         SetFlag( nFirstVisScTab, ExcTabBufFlags::Visible ); // must be visible, even if originally hidden
746     }
747 
748     // find currently displayed sheet
749     if( !IsExportTab( nDisplScTab ) )   // selected sheet not exported (i.e. scenario) -> use first visible
750         nDisplScTab = nFirstVisScTab;
751     SetFlag( nDisplScTab, ExcTabBufFlags::Visible | ExcTabBufFlags::Selected );
752 
753     // number of selected sheets
754     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
755         if( IsSelectedTab( nScTab ) )
756             ++mnXclSelCnt;
757 
758     // --- calculate resulting Excel sheet indexes ---
759 
760     CalcXclIndexes();
761     mnFirstVisXclTab = GetXclTab( nFirstVisScTab );
762     mnDisplXclTab = GetXclTab( nDisplScTab );
763 
764     // --- sorted vectors for index lookup ---
765 
766     CalcSortedIndexes();
767 }
768 
IsExportTab(SCTAB nScTab) const769 bool XclExpTabInfo::IsExportTab( SCTAB nScTab ) const
770 {
771     /*  Check sheet index before to avoid assertion in GetFlag(). */
772     return (nScTab < mnScCnt && nScTab >= 0) && !GetFlag( nScTab, ExcTabBufFlags::SkipMask );
773 }
774 
IsExternalTab(SCTAB nScTab) const775 bool XclExpTabInfo::IsExternalTab( SCTAB nScTab ) const
776 {
777     /*  Check sheet index before to avoid assertion (called from formula
778         compiler also for deleted references). */
779     return (nScTab < mnScCnt && nScTab >= 0) && GetFlag( nScTab, ExcTabBufFlags::Extern );
780 }
781 
IsVisibleTab(SCTAB nScTab) const782 bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab ) const
783 {
784     return GetFlag( nScTab, ExcTabBufFlags::Visible );
785 }
786 
IsSelectedTab(SCTAB nScTab) const787 bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab ) const
788 {
789     return GetFlag( nScTab, ExcTabBufFlags::Selected );
790 }
791 
IsDisplayedTab(SCTAB nScTab) const792 bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab ) const
793 {
794     OSL_ENSURE( nScTab < mnScCnt && nScTab >= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
795     return GetXclTab( nScTab ) == mnDisplXclTab;
796 }
797 
IsMirroredTab(SCTAB nScTab) const798 bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab ) const
799 {
800     return GetFlag( nScTab, ExcTabBufFlags::Mirrored );
801 }
802 
GetScTabName(SCTAB nScTab) const803 OUString XclExpTabInfo::GetScTabName( SCTAB nScTab ) const
804 {
805     OSL_ENSURE( nScTab < mnScCnt && nScTab >= 0, "XclExpTabInfo::IsActiveTab - sheet out of range" );
806     return (nScTab < mnScCnt && nScTab >= 0) ? maTabInfoVec[ nScTab ].maScName : OUString();
807 }
808 
GetXclTab(SCTAB nScTab) const809 sal_uInt16 XclExpTabInfo::GetXclTab( SCTAB nScTab ) const
810 {
811     return (nScTab < mnScCnt && nScTab >= 0) ? maTabInfoVec[ nScTab ].mnXclTab : EXC_TAB_DELETED;
812 }
813 
GetRealScTab(SCTAB nSortedScTab) const814 SCTAB XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab ) const
815 {
816     OSL_ENSURE( nSortedScTab < mnScCnt && nSortedScTab >= 0, "XclExpTabInfo::GetRealScTab - sheet out of range" );
817     return (nSortedScTab < mnScCnt && nSortedScTab >= 0) ? maFromSortedVec[ nSortedScTab ] : SCTAB_INVALID;
818 }
819 
GetFlag(SCTAB nScTab,ExcTabBufFlags nFlags) const820 bool XclExpTabInfo::GetFlag( SCTAB nScTab, ExcTabBufFlags nFlags ) const
821 {
822     OSL_ENSURE( nScTab < mnScCnt && nScTab >= 0, "XclExpTabInfo::GetFlag - sheet out of range" );
823     return (nScTab < mnScCnt && nScTab >= 0) && (maTabInfoVec[ nScTab ].mnFlags & nFlags);
824 }
825 
SetFlag(SCTAB nScTab,ExcTabBufFlags nFlags,bool bSet)826 void XclExpTabInfo::SetFlag( SCTAB nScTab, ExcTabBufFlags nFlags, bool bSet )
827 {
828     OSL_ENSURE( nScTab < mnScCnt && nScTab >= 0, "XclExpTabInfo::SetFlag - sheet out of range" );
829     if( nScTab < mnScCnt && nScTab >= 0 )
830     {
831         if (bSet)
832             maTabInfoVec[ nScTab ].mnFlags |= nFlags;
833         else
834             maTabInfoVec[ nScTab ].mnFlags &= ~nFlags;
835     }
836 }
837 
CalcXclIndexes()838 void XclExpTabInfo::CalcXclIndexes()
839 {
840     sal_uInt16 nXclTab = 0;
841     SCTAB nScTab = 0;
842 
843     // --- pass 1: process regular sheets ---
844     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
845     {
846         if( IsExportTab( nScTab ) )
847         {
848             maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
849             ++nXclTab;
850         }
851         else
852             maTabInfoVec[ nScTab ].mnXclTab = EXC_TAB_DELETED;
853     }
854     mnXclCnt = nXclTab;
855 
856     // --- pass 2: process external sheets (nXclTab continues) ---
857     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
858     {
859         if( IsExternalTab( nScTab ) )
860         {
861             maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
862             ++nXclTab;
863             ++mnXclExtCnt;
864         }
865     }
866 
867     // result: first occur all exported sheets, followed by all external sheets
868 }
869 
870 typedef ::std::pair< OUString, SCTAB > XclExpTabName;
871 
872 struct XclExpTabNameSort {
operator ()XclExpTabNameSort873     bool operator ()( const XclExpTabName& rArg1, const XclExpTabName& rArg2 )
874     {
875         // compare the sheet names only
876         return ScGlobal::GetCollator()->compareString( rArg1.first, rArg2.first ) < 0;
877     }
878 };
879 
CalcSortedIndexes()880 void XclExpTabInfo::CalcSortedIndexes()
881 {
882     ScDocument& rDoc = GetDoc();
883     ::std::vector< XclExpTabName > aVec( mnScCnt );
884     SCTAB nScTab;
885 
886     // fill with sheet names
887     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
888     {
889         rDoc.GetName( nScTab, aVec[ nScTab ].first );
890         aVec[ nScTab ].second = nScTab;
891     }
892     ::std::sort( aVec.begin(), aVec.end(), XclExpTabNameSort() );
893 
894     // fill index vectors from sorted sheet name vector
895     maFromSortedVec.resize( mnScCnt );
896     maToSortedVec.resize( mnScCnt );
897     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
898     {
899         maFromSortedVec[ nScTab ] = aVec[ nScTab ].second;
900         maToSortedVec[ aVec[ nScTab ].second ] = nScTab;
901     }
902 }
903 
904 // External names =============================================================
905 
XclExpExtNameBase(const XclExpRoot & rRoot,const OUString & rName,sal_uInt16 nFlags)906 XclExpExtNameBase::XclExpExtNameBase(
907         const XclExpRoot& rRoot, const OUString& rName, sal_uInt16 nFlags ) :
908     XclExpRecord( EXC_ID_EXTERNNAME ),
909     XclExpRoot( rRoot ),
910     maName( rName ),
911     mxName( XclExpStringHelper::CreateString( rRoot, rName, XclStrFlags::EightBitLength ) ),
912     mnFlags( nFlags )
913 {
914     OSL_ENSURE( maName.getLength() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
915     SetRecSize( 6 + mxName->GetSize() );
916 }
917 
WriteBody(XclExpStream & rStrm)918 void XclExpExtNameBase::WriteBody( XclExpStream& rStrm )
919 {
920     rStrm   << mnFlags
921             << sal_uInt32( 0 )
922             << *mxName;
923     WriteAddData( rStrm );
924 }
925 
WriteAddData(XclExpStream &)926 void XclExpExtNameBase::WriteAddData( XclExpStream& /*rStrm*/ )
927 {
928 }
929 
XclExpExtNameAddIn(const XclExpRoot & rRoot,const OUString & rName)930 XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot& rRoot, const OUString& rName ) :
931     XclExpExtNameBase( rRoot, rName )
932 {
933     AddRecSize( 4 );
934 }
935 
WriteAddData(XclExpStream & rStrm)936 void XclExpExtNameAddIn::WriteAddData( XclExpStream& rStrm )
937 {
938     // write a #REF! error formula
939     rStrm << sal_uInt16( 2 ) << EXC_TOKID_ERR << EXC_ERR_REF;
940 }
941 
XclExpExtNameDde(const XclExpRoot & rRoot,const OUString & rName,sal_uInt16 nFlags,const ScMatrix * pResults)942 XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot& rRoot,
943         const OUString& rName, sal_uInt16 nFlags, const ScMatrix* pResults ) :
944     XclExpExtNameBase( rRoot, rName, nFlags )
945 {
946     if( pResults )
947     {
948         mxMatrix.reset( new XclExpCachedMatrix( *pResults ) );
949         AddRecSize( mxMatrix->GetSize() );
950     }
951 }
952 
WriteAddData(XclExpStream & rStrm)953 void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
954 {
955     if( mxMatrix )
956         mxMatrix->Save( rStrm );
957 }
958 
XclExpExtName(const XclExpRoot & rRoot,const XclExpSupbook & rSupbook,const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)959 XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook,
960         const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray ) :
961     XclExpExtNameBase( rRoot, rName ),
962     mrSupbook(rSupbook),
963     mpArray(rArray->Clone())
964 {
965 }
966 
WriteAddData(XclExpStream & rStrm)967 void XclExpExtName::WriteAddData( XclExpStream& rStrm )
968 {
969     // Write only if it only has a single token that is either a cell or cell
970     // range address.  Excel just writes '02 00 1C 17' for all the other types
971     // of external names.
972 
973     using namespace ::formula;
974     do
975     {
976         if (mpArray->GetLen() != 1)
977             break;
978 
979         const formula::FormulaToken* p = mpArray->FirstToken();
980         if (!p->IsExternalRef())
981             break;
982 
983         switch (p->GetType())
984         {
985             case svExternalSingleRef:
986             {
987                 const ScSingleRefData& rRef = *p->GetSingleRef();
988                 if (rRef.IsTabRel())
989                     break;
990 
991                 bool bColRel = rRef.IsColRel();
992                 bool bRowRel = rRef.IsRowRel();
993                 sal_uInt16 nCol = static_cast<sal_uInt16>(rRef.Col());
994                 sal_uInt16 nRow = static_cast<sal_uInt16>(rRef.Row());
995                 if (bColRel) nCol |= 0x4000;
996                 if (bRowRel) nCol |= 0x8000;
997 
998                 OUString aTabName = p->GetString().getString();
999                 sal_uInt16 nSBTab = mrSupbook.GetTabIndex(aTabName);
1000 
1001                 // size is always 9
1002                 rStrm << static_cast<sal_uInt16>(9);
1003                 // operator token (3A for cell reference)
1004                 rStrm << static_cast<sal_uInt8>(0x3A);
1005                 // cell address (Excel's address has 2 sheet IDs.)
1006                 rStrm << nSBTab << nSBTab << nRow << nCol;
1007                 return;
1008             }
1009             case svExternalDoubleRef:
1010             {
1011                 const ScComplexRefData& rRef = *p->GetDoubleRef();
1012                 const ScSingleRefData& r1 = rRef.Ref1;
1013                 const ScSingleRefData& r2 = rRef.Ref2;
1014                 if (r1.IsTabRel() || r2.IsTabRel())
1015                     break;
1016 
1017                 sal_uInt16 nTab1 = r1.Tab();
1018                 sal_uInt16 nTab2 = r2.Tab();
1019                 bool bCol1Rel = r1.IsColRel();
1020                 bool bRow1Rel = r1.IsRowRel();
1021                 bool bCol2Rel = r2.IsColRel();
1022                 bool bRow2Rel = r2.IsRowRel();
1023 
1024                 sal_uInt16 nCol1 = static_cast<sal_uInt16>(r1.Col());
1025                 sal_uInt16 nCol2 = static_cast<sal_uInt16>(r2.Col());
1026                 sal_uInt16 nRow1 = static_cast<sal_uInt16>(r1.Row());
1027                 sal_uInt16 nRow2 = static_cast<sal_uInt16>(r2.Row());
1028                 if (bCol1Rel) nCol1 |= 0x4000;
1029                 if (bRow1Rel) nCol1 |= 0x8000;
1030                 if (bCol2Rel) nCol2 |= 0x4000;
1031                 if (bRow2Rel) nCol2 |= 0x8000;
1032 
1033                 OUString aTabName = p->GetString().getString();
1034                 sal_uInt16 nSBTab = mrSupbook.GetTabIndex(aTabName);
1035 
1036                 // size is always 13 (0x0D)
1037                 rStrm << static_cast<sal_uInt16>(13);
1038                 // operator token (3B for area reference)
1039                 rStrm << static_cast<sal_uInt8>(0x3B);
1040                 // range (area) address
1041                 sal_uInt16 nSBTab2 = nSBTab + nTab2 - nTab1;
1042                 rStrm << nSBTab << nSBTab2 << nRow1 << nRow2 << nCol1 << nCol2;
1043                 return;
1044             }
1045             default:
1046                 ;   // nothing
1047         }
1048     }
1049     while (false);
1050 
1051     // special value for #REF! (02 00 1C 17)
1052     rStrm << static_cast<sal_uInt16>(2) << EXC_TOKID_ERR << EXC_ERR_REF;
1053 }
1054 
SaveXml(XclExpXmlStream & rStrm)1055 void XclExpExtName::SaveXml(XclExpXmlStream& rStrm)
1056 {
1057     sax_fastparser::FSHelperPtr pExternalLink = rStrm.GetCurrentStream();
1058 
1059     pExternalLink->startElement(XML_definedName,
1060             XML_name, maName.toUtf8(),
1061             XML_refersTo, nullptr,
1062             XML_sheetId, nullptr);
1063 
1064     pExternalLink->endElement(XML_definedName);
1065 }
1066 
1067 // List of external names =====================================================
1068 
XclExpExtNameBuffer(const XclExpRoot & rRoot)1069 XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
1070     XclExpRoot( rRoot )
1071 {
1072 }
1073 
InsertAddIn(const OUString & rName)1074 sal_uInt16 XclExpExtNameBuffer::InsertAddIn( const OUString& rName )
1075 {
1076     sal_uInt16 nIndex = GetIndex( rName );
1077     return nIndex ? nIndex : AppendNew( new XclExpExtNameAddIn( GetRoot(), rName ) );
1078 }
1079 
InsertEuroTool(const OUString & rName)1080 sal_uInt16 XclExpExtNameBuffer::InsertEuroTool( const OUString& rName )
1081 {
1082     sal_uInt16 nIndex = GetIndex( rName );
1083     return nIndex ? nIndex : AppendNew( new XclExpExtNameBase( GetRoot(), rName ) );
1084 }
1085 
InsertDde(const OUString & rApplic,const OUString & rTopic,const OUString & rItem)1086 sal_uInt16 XclExpExtNameBuffer::InsertDde(
1087         const OUString& rApplic, const OUString& rTopic, const OUString& rItem )
1088 {
1089     sal_uInt16 nIndex = GetIndex( rItem );
1090     if( nIndex == 0 )
1091     {
1092         size_t nPos;
1093         if( GetDoc().FindDdeLink( rApplic, rTopic, rItem, SC_DDE_IGNOREMODE, nPos ) )
1094         {
1095             // create the leading 'StdDocumentName' EXTERNNAME record
1096             if( maNameList.IsEmpty() )
1097                 AppendNew( new XclExpExtNameDde(
1098                     GetRoot(), "StdDocumentName", EXC_EXTN_EXPDDE_STDDOC ) );
1099 
1100             // try to find DDE result array, but create EXTERNNAME record without them too
1101             const ScMatrix* pScMatrix = GetDoc().GetDdeLinkResultMatrix( nPos );
1102             nIndex = AppendNew( new XclExpExtNameDde( GetRoot(), rItem, EXC_EXTN_EXPDDE, pScMatrix ) );
1103         }
1104     }
1105     return nIndex;
1106 }
1107 
InsertExtName(const XclExpSupbook & rSupbook,const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)1108 sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook,
1109         const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray )
1110 {
1111     sal_uInt16 nIndex = GetIndex( rName );
1112     return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, rArray ) );
1113 }
1114 
Save(XclExpStream & rStrm)1115 void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
1116 {
1117     maNameList.Save( rStrm );
1118 }
1119 
SaveXml(XclExpXmlStream & rStrm)1120 void XclExpExtNameBuffer::SaveXml(XclExpXmlStream& rStrm)
1121 {
1122     maNameList.SaveXml(rStrm);
1123 }
1124 
GetIndex(const OUString & rName) const1125 sal_uInt16 XclExpExtNameBuffer::GetIndex( const OUString& rName ) const
1126 {
1127     for( size_t nPos = 0, nSize = maNameList.GetSize(); nPos < nSize; ++nPos )
1128         if( maNameList.GetRecord( nPos )->GetName() == rName )
1129             return static_cast< sal_uInt16 >( nPos + 1 );
1130     return 0;
1131 }
1132 
AppendNew(XclExpExtNameBase * pExtName)1133 sal_uInt16 XclExpExtNameBuffer::AppendNew( XclExpExtNameBase* pExtName )
1134 {
1135     XclExpExtNameRef xExtName( pExtName );
1136     size_t nSize = maNameList.GetSize();
1137     if( nSize < 0x7FFF )
1138     {
1139         maNameList.AppendRecord( xExtName );
1140         return static_cast< sal_uInt16 >( nSize + 1 );
1141     }
1142     return 0;
1143 }
1144 
1145 // Cached external cells ======================================================
1146 
XclExpCrn(SCCOL nScCol,SCROW nScRow,const Any & rValue)1147 XclExpCrn::XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue ) :
1148     XclExpRecord( EXC_ID_CRN, 4 ),
1149     mnScCol( nScCol ),
1150     mnScRow( nScRow )
1151 {
1152     maValues.push_back( rValue );
1153 }
1154 
InsertValue(SCCOL nScCol,SCROW nScRow,const Any & rValue)1155 bool XclExpCrn::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
1156 {
1157     if( (nScRow != mnScRow) || (nScCol != static_cast< SCCOL >( mnScCol + maValues.size() )) )
1158         return false;
1159     maValues.push_back( rValue );
1160     return true;
1161 }
1162 
WriteBody(XclExpStream & rStrm)1163 void XclExpCrn::WriteBody( XclExpStream& rStrm )
1164 {
1165     rStrm   << static_cast< sal_uInt8 >( mnScCol + maValues.size() - 1 )
1166             << static_cast< sal_uInt8 >( mnScCol )
1167             << static_cast< sal_uInt16 >( mnScRow );
1168     for( const auto& rValue : maValues )
1169     {
1170         if( rValue.has< bool >() )
1171             WriteBool( rStrm, rValue.get< bool >() );
1172         else if( rValue.has< double >() )
1173             WriteDouble( rStrm, rValue.get< double >() );
1174         else if( rValue.has< OUString >() )
1175             WriteString( rStrm, rValue.get< OUString >() );
1176         else
1177             WriteEmpty( rStrm );
1178     }
1179 }
1180 
WriteBool(XclExpStream & rStrm,bool bValue)1181 void XclExpCrn::WriteBool( XclExpStream& rStrm, bool bValue )
1182 {
1183     rStrm << EXC_CACHEDVAL_BOOL << sal_uInt8( bValue ? 1 : 0);
1184     rStrm.WriteZeroBytes( 7 );
1185 }
1186 
WriteDouble(XclExpStream & rStrm,double fValue)1187 void XclExpCrn::WriteDouble( XclExpStream& rStrm, double fValue )
1188 {
1189     if( !::rtl::math::isFinite( fValue ) )
1190     {
1191         FormulaError nScError = GetDoubleErrorValue(fValue);
1192         WriteError( rStrm, XclTools::GetXclErrorCode( nScError ) );
1193     }
1194     else
1195     {
1196         rStrm << EXC_CACHEDVAL_DOUBLE << fValue;
1197     }
1198 }
1199 
WriteString(XclExpStream & rStrm,const OUString & rValue)1200 void XclExpCrn::WriteString( XclExpStream& rStrm, const OUString& rValue )
1201 {
1202     rStrm << EXC_CACHEDVAL_STRING << XclExpString( rValue );
1203 }
1204 
WriteError(XclExpStream & rStrm,sal_uInt8 nErrCode)1205 void XclExpCrn::WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode )
1206 {
1207     rStrm << EXC_CACHEDVAL_ERROR << nErrCode;
1208     rStrm.WriteZeroBytes( 7 );
1209 }
1210 
WriteEmpty(XclExpStream & rStrm)1211 void XclExpCrn::WriteEmpty( XclExpStream& rStrm )
1212 {
1213     rStrm << EXC_CACHEDVAL_EMPTY;
1214     rStrm.WriteZeroBytes( 8 );
1215 }
1216 
SaveXml(XclExpXmlStream & rStrm)1217 void XclExpCrn::SaveXml( XclExpXmlStream& rStrm )
1218 {
1219     sax_fastparser::FSHelperPtr pFS = rStrm.GetCurrentStream();
1220 
1221     pFS->startElement(XML_row, XML_r, OString::number(mnScRow + 1));
1222 
1223     ScAddress aAdr( mnScCol, mnScRow, 0);   // Tab number doesn't matter
1224     for( const auto& rValue : maValues )
1225     {
1226         bool bCloseCell = true;
1227         if( rValue.has< double >() )
1228         {
1229             double fVal = rValue.get< double >();
1230             if (rtl::math::isFinite( fVal))
1231             {
1232                 // t='n' is omitted
1233                 pFS->startElement(XML_cell, XML_r, XclXmlUtils::ToOString(&rStrm.GetRoot().GetDoc(), aAdr));
1234                 pFS->startElement(XML_v);
1235                 pFS->write( fVal );
1236             }
1237             else
1238             {
1239                 pFS->startElement(XML_cell, XML_r, XclXmlUtils::ToOString(&rStrm.GetRoot().GetDoc(), aAdr), XML_t, "e");
1240                 pFS->startElement(XML_v);
1241                 pFS->write( "#VALUE!" );    // OOXTODO: support other error values
1242             }
1243         }
1244         else if( rValue.has< OUString >() )
1245         {
1246             pFS->startElement(XML_cell, XML_r, XclXmlUtils::ToOString(&rStrm.GetRoot().GetDoc(), aAdr), XML_t, "str");
1247             pFS->startElement(XML_v);
1248             pFS->write( rValue.get< OUString >() );
1249         }
1250         else if( rValue.has< bool >() )
1251         {
1252             pFS->startElement(XML_cell, XML_r, XclXmlUtils::ToOString(&rStrm.GetRoot().GetDoc(), aAdr), XML_t, "b");
1253             pFS->startElement(XML_v);
1254             pFS->write( rValue.get< bool >() ? "1" : "0" );
1255         }
1256         // OOXTODO: error type cell t='e'
1257         else
1258         {
1259             // Empty/blank cell not stored, only aAdr is incremented.
1260             bCloseCell = false;
1261         }
1262         if (bCloseCell)
1263         {
1264             pFS->endElement(XML_v);
1265             pFS->endElement(XML_cell);
1266         }
1267         aAdr.IncCol();
1268     }
1269 
1270     pFS->endElement( XML_row);
1271 }
1272 
1273 // Cached cells of a sheet ====================================================
1274 
XclExpXct(const XclExpRoot & rRoot,const OUString & rTabName,sal_uInt16 nSBTab,ScExternalRefCache::TableTypeRef const & xCacheTable)1275 XclExpXct::XclExpXct( const XclExpRoot& rRoot, const OUString& rTabName,
1276         sal_uInt16 nSBTab, ScExternalRefCache::TableTypeRef const & xCacheTable ) :
1277     XclExpRoot( rRoot ),
1278     mxCacheTable( xCacheTable ),
1279     maUsedCells( MAXROW, MAXCOL ),
1280     maBoundRange( ScAddress::INITIALIZE_INVALID ),
1281     maTabName( rTabName ),
1282     mnSBTab( nSBTab )
1283 {
1284 }
1285 
StoreCellRange(const ScRange & rRange)1286 void XclExpXct::StoreCellRange( const ScRange& rRange )
1287 {
1288     // #i70418# restrict size of external range to prevent memory overflow
1289     if( (rRange.aEnd.Col() - rRange.aStart.Col()) * (rRange.aEnd.Row() - rRange.aStart.Row()) > 1024 )
1290         return;
1291 
1292     maUsedCells.SetMultiMarkArea( rRange );
1293     maBoundRange.ExtendTo( rRange );
1294 }
1295 
StoreCell_(const ScAddress & rCell)1296 void XclExpXct::StoreCell_( const ScAddress& rCell )
1297 {
1298     maUsedCells.SetMultiMarkArea( ScRange( rCell ) );
1299     maBoundRange.ExtendTo( ScRange( rCell ) );
1300 }
1301 
StoreCellRange_(const ScRange & rRange)1302 void XclExpXct::StoreCellRange_( const ScRange& rRange )
1303 {
1304     maUsedCells.SetMultiMarkArea( rRange );
1305     maBoundRange.ExtendTo( rRange );
1306 }
1307 
1308 namespace {
1309 
1310 class XclExpCrnList : public XclExpRecordList< XclExpCrn >
1311 {
1312 public:
1313     /** Inserts the passed value into an existing or new CRN record.
1314         @return  True = value inserted successfully, false = CRN list is full. */
1315     bool                InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
1316 };
1317 
InsertValue(SCCOL nScCol,SCROW nScRow,const Any & rValue)1318 bool XclExpCrnList::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
1319 {
1320     RecordRefType xLastRec = GetLastRecord();
1321     if( xLastRec && xLastRec->InsertValue( nScCol, nScRow, rValue ) )
1322         return true;
1323     if( GetSize() == SAL_MAX_UINT16 )
1324         return false;
1325     AppendNewRecord( new XclExpCrn( nScCol, nScRow, rValue ) );
1326     return true;
1327 }
1328 
1329 } // namespace
1330 
BuildCrnList(XclExpCrnList & rCrnRecs)1331 bool XclExpXct::BuildCrnList( XclExpCrnList& rCrnRecs )
1332 {
1333     if( !mxCacheTable )
1334         return false;
1335 
1336     /*  Get the range of used rows in the cache table. This may help to
1337         optimize building the CRN record list if the cache table does not
1338         contain all referred cells, e.g. if big empty ranges are used in the
1339         formulas. */
1340     ::std::pair< SCROW, SCROW > aRowRange = mxCacheTable->getRowRange();
1341     if( aRowRange.first >= aRowRange.second )
1342         return false;
1343 
1344     /*  Crop the bounding range of used cells in this table to Excel limits.
1345         Return if there is no external cell inside these limits. */
1346     if( !GetAddressConverter().ValidateRange( maBoundRange, false ) )
1347         return false;
1348 
1349     /*  Find the resulting row range that needs to be processed. */
1350     SCROW nScRow1 = ::std::max( aRowRange.first, maBoundRange.aStart.Row() );
1351     SCROW nScRow2 = ::std::min( aRowRange.second - 1, maBoundRange.aEnd.Row() );
1352     if( nScRow1 > nScRow2 )
1353         return false;
1354 
1355     /*  Build and collect all CRN records before writing the XCT record. This
1356         is needed to determine the total number of CRN records which must be
1357         known when writing the XCT record (possibly encrypted, so seeking the
1358         output stream back after writing the CRN records is not an option). */
1359     SvNumberFormatter& rFormatter = GetFormatter();
1360     bool bValid = true;
1361     for( SCROW nScRow = nScRow1; bValid && (nScRow <= nScRow2); ++nScRow )
1362     {
1363         ::std::pair< SCCOL, SCCOL > aColRange = mxCacheTable->getColRange( nScRow );
1364         const SCCOL nScEnd = ::std::min( aColRange.second, MAXCOLCOUNT );
1365         for( SCCOL nScCol = aColRange.first; bValid && (nScCol < nScEnd); ++nScCol )
1366         {
1367             if( maUsedCells.IsCellMarked( nScCol, nScRow, true ) )
1368             {
1369                 sal_uInt32 nScNumFmt = 0;
1370                 ScExternalRefCache::TokenRef xToken = mxCacheTable->getCell( nScCol, nScRow, &nScNumFmt );
1371                 using namespace ::formula;
1372                 if( xToken.get() ) switch( xToken->GetType() )
1373                 {
1374                     case svDouble:
1375                         bValid = (rFormatter.GetType( nScNumFmt ) == SvNumFormatType::LOGICAL) ?
1376                             rCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() != 0 ) ) :
1377                             rCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() ) );
1378                     break;
1379                     case svString:
1380                         // do not save empty strings (empty cells) to cache
1381                         if( !xToken->GetString().isEmpty() )
1382                             bValid = rCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetString().getString() ) );
1383                     break;
1384                     default:
1385                     break;
1386                 }
1387             }
1388         }
1389     }
1390     return true;
1391 }
1392 
Save(XclExpStream & rStrm)1393 void XclExpXct::Save( XclExpStream& rStrm )
1394 {
1395     XclExpCrnList aCrnRecs;
1396     if (!BuildCrnList( aCrnRecs))
1397         return;
1398 
1399     // write the XCT record and the list of CRN records
1400     rStrm.StartRecord( EXC_ID_XCT, 4 );
1401     rStrm << static_cast< sal_uInt16 >( aCrnRecs.GetSize() ) << mnSBTab;
1402     rStrm.EndRecord();
1403     aCrnRecs.Save( rStrm );
1404 }
1405 
SaveXml(XclExpXmlStream & rStrm)1406 void XclExpXct::SaveXml( XclExpXmlStream& rStrm )
1407 {
1408     XclExpCrnList aCrnRecs;
1409 
1410     sax_fastparser::FSHelperPtr pFS = rStrm.GetCurrentStream();
1411 
1412     bool bValid = BuildCrnList( aCrnRecs);
1413     pFS->startElement(XML_sheetData, XML_sheetId, OString::number(mnSBTab));
1414     if (bValid)
1415     {
1416         // row elements
1417         aCrnRecs.SaveXml( rStrm );
1418     }
1419     pFS->endElement( XML_sheetData);
1420 }
1421 
1422 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
1423 
XclExpExternSheetBase(const XclExpRoot & rRoot,sal_uInt16 nRecId,sal_uInt32 nRecSize)1424 XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot& rRoot, sal_uInt16 nRecId, sal_uInt32 nRecSize ) :
1425     XclExpRecord( nRecId, nRecSize ),
1426     XclExpRoot( rRoot )
1427 {
1428 }
1429 
GetExtNameBuffer()1430 XclExpExtNameBuffer& XclExpExternSheetBase::GetExtNameBuffer()
1431 {
1432     if( !mxExtNameBfr )
1433         mxExtNameBfr.reset( new XclExpExtNameBuffer( GetRoot() ) );
1434     return *mxExtNameBfr;
1435 }
1436 
WriteExtNameBuffer(XclExpStream & rStrm)1437 void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream& rStrm )
1438 {
1439     if( mxExtNameBfr )
1440         mxExtNameBfr->Save( rStrm );
1441 }
1442 
WriteExtNameBufferXml(XclExpXmlStream & rStrm)1443 void XclExpExternSheetBase::WriteExtNameBufferXml( XclExpXmlStream& rStrm )
1444 {
1445     if( mxExtNameBfr )
1446         mxExtNameBfr->SaveXml( rStrm );
1447 }
1448 
1449 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
1450 
XclExpExternSheet(const XclExpRoot & rRoot,sal_Unicode cCode)1451 XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode ) :
1452     XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
1453 {
1454     Init( OUString(cCode) );
1455 }
1456 
XclExpExternSheet(const XclExpRoot & rRoot,const OUString & rTabName)1457 XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, const OUString& rTabName ) :
1458     XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
1459 {
1460     // reference to own sheet: \03<sheetname>
1461     Init(OUStringChar(EXC_EXTSH_TABNAME) + rTabName);
1462 }
1463 
Save(XclExpStream & rStrm)1464 void XclExpExternSheet::Save( XclExpStream& rStrm )
1465 {
1466     // EXTERNSHEET record
1467     XclExpRecord::Save( rStrm );
1468     // EXTERNNAME records
1469     WriteExtNameBuffer( rStrm );
1470 }
1471 
Init(const OUString & rEncUrl)1472 void XclExpExternSheet::Init( const OUString& rEncUrl )
1473 {
1474     OSL_ENSURE_BIFF( GetBiff() <= EXC_BIFF5 );
1475     maTabName.AssignByte( rEncUrl, GetTextEncoding(), XclStrFlags::EightBitLength );
1476     SetRecSize( maTabName.GetSize() );
1477 }
1478 
InsertAddIn(const OUString & rName)1479 sal_uInt16 XclExpExternSheet::InsertAddIn( const OUString& rName )
1480 {
1481     return GetExtNameBuffer().InsertAddIn( rName );
1482 }
1483 
WriteBody(XclExpStream & rStrm)1484 void XclExpExternSheet::WriteBody( XclExpStream& rStrm )
1485 {
1486     sal_uInt8 nNameSize = static_cast< sal_uInt8 >( maTabName.Len() );
1487     // special case: reference to own sheet (starting with '\03') needs wrong string length
1488     if( maTabName.GetChar( 0 ) == EXC_EXTSH_TABNAME )
1489         --nNameSize;
1490     rStrm << nNameSize;
1491     maTabName.WriteBuffer( rStrm );
1492 }
1493 
1494 // External document (SUPBOOK, BIFF8) =========================================
1495 
XclExpSupbook(const XclExpRoot & rRoot,sal_uInt16 nXclTabCount)1496 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount ) :
1497     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1498     meType( XclSupbookType::Self ),
1499     mnXclTabCount( nXclTabCount ),
1500     mnFileId( 0 )
1501 {
1502 }
1503 
XclExpSupbook(const XclExpRoot & rRoot)1504 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot ) :
1505     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1506     meType( XclSupbookType::Addin ),
1507     mnXclTabCount( 1 ),
1508     mnFileId( 0 )
1509 {
1510 }
1511 
XclExpSupbook(const XclExpRoot & rRoot,const OUString & rUrl,XclSupbookType)1512 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const OUString& rUrl, XclSupbookType ) :
1513     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
1514     maUrl( rUrl ),
1515     maUrlEncoded( rUrl ),
1516     meType( XclSupbookType::Eurotool ),
1517     mnXclTabCount( 0 ),
1518     mnFileId( 0 )
1519 {
1520     SetRecSize( 2 + maUrlEncoded.GetSize() );
1521 }
1522 
XclExpSupbook(const XclExpRoot & rRoot,const OUString & rUrl)1523 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const OUString& rUrl ) :
1524     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
1525     maUrl( rUrl ),
1526     maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot, rUrl ) ),
1527     meType( XclSupbookType::Extern ),
1528     mnXclTabCount( 0 ),
1529     mnFileId( 0 )
1530 {
1531     SetRecSize( 2 + maUrlEncoded.GetSize() );
1532 
1533     // We need to create all tables up front to ensure the correct table order.
1534     ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager();
1535     sal_uInt16 nFileId = pRefMgr->getExternalFileId( rUrl );
1536     mnFileId = nFileId + 1;
1537     ScfStringVec aTabNames;
1538     pRefMgr->getAllCachedTableNames( nFileId, aTabNames );
1539     size_t nTabIndex = 0;
1540     for( const auto& rTabName : aTabNames )
1541     {
1542         InsertTabName( rTabName, pRefMgr->getCacheTable( nFileId, nTabIndex ) );
1543         ++nTabIndex;
1544     }
1545 }
1546 
XclExpSupbook(const XclExpRoot & rRoot,const OUString & rApplic,const OUString & rTopic)1547 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const OUString& rApplic, const OUString& rTopic ) :
1548     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1549     maUrl( rApplic ),
1550     maDdeTopic( rTopic ),
1551     maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic, rTopic ) ),
1552     meType( XclSupbookType::Special ),
1553     mnXclTabCount( 0 ),
1554     mnFileId( 0 )
1555 {
1556     SetRecSize( 2 + maUrlEncoded.GetSize() );
1557 }
1558 
IsUrlLink(const OUString & rUrl) const1559 bool XclExpSupbook::IsUrlLink( const OUString& rUrl ) const
1560 {
1561     return (meType == XclSupbookType::Extern || meType == XclSupbookType::Eurotool) && (maUrl == rUrl);
1562 }
1563 
IsDdeLink(const OUString & rApplic,const OUString & rTopic) const1564 bool XclExpSupbook::IsDdeLink( const OUString& rApplic, const OUString& rTopic ) const
1565 {
1566     return (meType == XclSupbookType::Special) && (maUrl == rApplic) && (maDdeTopic == rTopic);
1567 }
1568 
FillRefLogEntry(XclExpRefLogEntry & rRefLogEntry,sal_uInt16 nFirstSBTab,sal_uInt16 nLastSBTab) const1569 void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
1570         sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const
1571 {
1572     rRefLogEntry.mpUrl = maUrlEncoded.IsEmpty() ? nullptr : &maUrlEncoded;
1573     rRefLogEntry.mpFirstTab = GetTabName( nFirstSBTab );
1574     rRefLogEntry.mpLastTab = GetTabName( nLastSBTab );
1575 }
1576 
StoreCellRange(const ScRange & rRange,sal_uInt16 nSBTab)1577 void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
1578 {
1579     if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1580         pXct->StoreCellRange( rRange );
1581 }
1582 
StoreCell_(sal_uInt16 nSBTab,const ScAddress & rCell)1583 void XclExpSupbook::StoreCell_( sal_uInt16 nSBTab, const ScAddress& rCell )
1584 {
1585     if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1586         pXct->StoreCell_( rCell );
1587 }
1588 
StoreCellRange_(sal_uInt16 nSBTab,const ScRange & rRange)1589 void XclExpSupbook::StoreCellRange_( sal_uInt16 nSBTab, const ScRange& rRange )
1590 {
1591     // multi-table range is not allowed!
1592     if( rRange.aStart.Tab() == rRange.aEnd.Tab() )
1593         if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1594             pXct->StoreCellRange_( rRange );
1595 }
1596 
GetTabIndex(const OUString & rTabName) const1597 sal_uInt16 XclExpSupbook::GetTabIndex( const OUString& rTabName ) const
1598 {
1599     XclExpString aXclName(rTabName);
1600     size_t nSize = maXctList.GetSize();
1601     for (size_t i = 0; i < nSize; ++i)
1602     {
1603         XclExpXctRef aRec = maXctList.GetRecord(i);
1604         if (aXclName == aRec->GetTabName())
1605             return ulimit_cast<sal_uInt16>(i);
1606     }
1607     return EXC_NOTAB;
1608 }
1609 
GetTabCount() const1610 sal_uInt16 XclExpSupbook::GetTabCount() const
1611 {
1612     return ulimit_cast<sal_uInt16>(maXctList.GetSize());
1613 }
1614 
InsertTabName(const OUString & rTabName,ScExternalRefCache::TableTypeRef const & xCacheTable)1615 sal_uInt16 XclExpSupbook::InsertTabName( const OUString& rTabName, ScExternalRefCache::TableTypeRef const & xCacheTable )
1616 {
1617     SAL_WARN_IF( meType != XclSupbookType::Extern, "sc.filter", "Don't insert sheet names here" );
1618     sal_uInt16 nSBTab = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
1619     XclExpXctRef xXct( new XclExpXct( GetRoot(), rTabName, nSBTab, xCacheTable ) );
1620     AddRecSize( xXct->GetTabName().GetSize() );
1621     maXctList.AppendRecord( xXct );
1622     return nSBTab;
1623 }
1624 
InsertAddIn(const OUString & rName)1625 sal_uInt16 XclExpSupbook::InsertAddIn( const OUString& rName )
1626 {
1627     return GetExtNameBuffer().InsertAddIn( rName );
1628 }
1629 
InsertEuroTool(const OUString & rName)1630 sal_uInt16 XclExpSupbook::InsertEuroTool( const OUString& rName )
1631 {
1632     return GetExtNameBuffer().InsertEuroTool( rName );
1633 }
1634 
InsertDde(const OUString & rItem)1635 sal_uInt16 XclExpSupbook::InsertDde( const OUString& rItem )
1636 {
1637     return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
1638 }
1639 
InsertExtName(const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)1640 sal_uInt16 XclExpSupbook::InsertExtName( const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray )
1641 {
1642     return GetExtNameBuffer().InsertExtName(*this, rName, rArray);
1643 }
1644 
GetType() const1645 XclSupbookType XclExpSupbook::GetType() const
1646 {
1647     return meType;
1648 }
1649 
GetFileId() const1650 sal_uInt16 XclExpSupbook::GetFileId() const
1651 {
1652     return mnFileId;
1653 }
1654 
GetUrl() const1655 const OUString& XclExpSupbook::GetUrl() const
1656 {
1657     return maUrl;
1658 }
1659 
Save(XclExpStream & rStrm)1660 void XclExpSupbook::Save( XclExpStream& rStrm )
1661 {
1662     // SUPBOOK record
1663     XclExpRecord::Save( rStrm );
1664     // XCT record, CRN records
1665     maXctList.Save( rStrm );
1666     // EXTERNNAME records
1667     WriteExtNameBuffer( rStrm );
1668 }
1669 
SaveXml(XclExpXmlStream & rStrm)1670 void XclExpSupbook::SaveXml( XclExpXmlStream& rStrm )
1671 {
1672     sax_fastparser::FSHelperPtr pExternalLink = rStrm.GetCurrentStream();
1673 
1674     // Add relation for this stream, e.g. xl/externalLinks/_rels/externalLink1.xml.rels
1675     sal_uInt16 nLevel = 0;
1676     bool bRel = true;
1677     OUString sId = rStrm.addRelation( pExternalLink->getOutputStream(),
1678             oox::getRelationship(Relationship::EXTERNALLINKPATH),
1679             XclExpHyperlink::BuildFileName( nLevel, bRel, maUrl, GetRoot(), true),
1680             true );
1681 
1682     pExternalLink->startElement( XML_externalLink,
1683             XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8());
1684 
1685     pExternalLink->startElement( XML_externalBook,
1686             FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
1687             FSNS(XML_r, XML_id),    sId.toUtf8());
1688 
1689     if (!maXctList.IsEmpty())
1690     {
1691         pExternalLink->startElement(XML_sheetNames);
1692         for (size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos)
1693         {
1694             pExternalLink->singleElement(XML_sheetName,
1695                 XML_val, XclXmlUtils::ToOString(maXctList.GetRecord(nPos)->GetTabName()));
1696         }
1697         pExternalLink->endElement( XML_sheetNames);
1698 
1699     }
1700 
1701     if (mxExtNameBfr)
1702     {
1703         pExternalLink->startElement(XML_definedNames);
1704         // externalName elements
1705         WriteExtNameBufferXml( rStrm );
1706         pExternalLink->endElement(XML_definedNames);
1707     }
1708 
1709     if (!maXctList.IsEmpty())
1710     {
1711         pExternalLink->startElement(XML_sheetDataSet);
1712 
1713         // sheetData elements
1714         maXctList.SaveXml( rStrm );
1715 
1716         pExternalLink->endElement( XML_sheetDataSet);
1717 
1718     }
1719     pExternalLink->endElement( XML_externalBook);
1720     pExternalLink->endElement( XML_externalLink);
1721 }
1722 
GetTabName(sal_uInt16 nSBTab) const1723 const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
1724 {
1725     XclExpXctRef xXct = maXctList.GetRecord( nSBTab );
1726     return xXct ? &xXct->GetTabName() : nullptr;
1727 }
1728 
WriteBody(XclExpStream & rStrm)1729 void XclExpSupbook::WriteBody( XclExpStream& rStrm )
1730 {
1731     switch( meType )
1732     {
1733         case XclSupbookType::Self:
1734             rStrm << mnXclTabCount << EXC_SUPB_SELF;
1735         break;
1736         case XclSupbookType::Extern:
1737         case XclSupbookType::Special:
1738         case XclSupbookType::Eurotool:
1739         {
1740             sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
1741             rStrm << nCount << maUrlEncoded;
1742 
1743             for( size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos )
1744                 rStrm << maXctList.GetRecord( nPos )->GetTabName();
1745         }
1746         break;
1747         case XclSupbookType::Addin:
1748             rStrm << mnXclTabCount << EXC_SUPB_ADDIN;
1749         break;
1750         default:
1751             SAL_WARN( "sc.filter", "Unhandled SUPBOOK type " << meType);
1752     }
1753 }
1754 
1755 // All SUPBOOKS in a document =================================================
1756 
XclExpSupbookBuffer(const XclExpRoot & rRoot)1757 XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
1758     XclExpRoot( rRoot ),
1759     mnOwnDocSB( SAL_MAX_UINT16 ),
1760     mnAddInSB( SAL_MAX_UINT16 )
1761 {
1762     XclExpTabInfo& rTabInfo = GetTabInfo();
1763     sal_uInt16 nXclCnt = rTabInfo.GetXclTabCount();
1764     sal_uInt16 nCodeCnt = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
1765     size_t nCount = nXclCnt + rTabInfo.GetXclExtTabCount();
1766 
1767     OSL_ENSURE( nCount > 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
1768     if( nCount )
1769     {
1770         maSBIndexVec.resize( nCount );
1771 
1772         // self-ref SUPBOOK first of list
1773         XclExpSupbookRef xSupbook( new XclExpSupbook( GetRoot(), ::std::max( nXclCnt, nCodeCnt ) ) );
1774         mnOwnDocSB = Append( xSupbook );
1775         for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
1776             maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
1777     }
1778 }
1779 
GetXti(sal_uInt16 nFirstXclTab,sal_uInt16 nLastXclTab,XclExpRefLogEntry * pRefLogEntry) const1780 XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
1781         XclExpRefLogEntry* pRefLogEntry ) const
1782 {
1783     XclExpXti aXti;
1784     size_t nSize = maSBIndexVec.size();
1785     if( (nFirstXclTab < nSize) && (nLastXclTab < nSize) )
1786     {
1787         // index of the SUPBOOK record
1788         aXti.mnSupbook = maSBIndexVec[ nFirstXclTab ].mnSupbook;
1789 
1790         // all sheets in the same supbook?
1791         bool bSameSB = true;
1792         for( sal_uInt16 nXclTab = nFirstXclTab + 1; bSameSB && (nXclTab <= nLastXclTab); ++nXclTab )
1793         {
1794             bSameSB = maSBIndexVec[ nXclTab ].mnSupbook == aXti.mnSupbook;
1795             if( !bSameSB )
1796                 nLastXclTab = nXclTab - 1;
1797         }
1798         aXti.mnFirstSBTab = maSBIndexVec[ nFirstXclTab ].mnSBTab;
1799         aXti.mnLastSBTab = maSBIndexVec[ nLastXclTab ].mnSBTab;
1800 
1801         // fill external reference log entry (for change tracking)
1802         if( pRefLogEntry )
1803         {
1804             pRefLogEntry->mnFirstXclTab = nFirstXclTab;
1805             pRefLogEntry->mnLastXclTab = nLastXclTab;
1806             XclExpSupbookRef xSupbook = maSupbookList.GetRecord( aXti.mnSupbook );
1807             if( xSupbook )
1808                 xSupbook->FillRefLogEntry( *pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab );
1809         }
1810     }
1811     else
1812     {
1813         // special range, i.e. for deleted sheets or add-ins
1814         aXti.mnSupbook = mnOwnDocSB;
1815         aXti.mnFirstSBTab = nFirstXclTab;
1816         aXti.mnLastSBTab = nLastXclTab;
1817     }
1818 
1819     return aXti;
1820 }
1821 
StoreCellRange(const ScRange & rRange)1822 void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
1823 {
1824     sal_uInt16 nXclTab = GetTabInfo().GetXclTab( rRange.aStart.Tab() );
1825     if( nXclTab < maSBIndexVec.size() )
1826     {
1827         const XclExpSBIndex& rSBIndex = maSBIndexVec[ nXclTab ];
1828         XclExpSupbookRef xSupbook = maSupbookList.GetRecord( rSBIndex.mnSupbook );
1829         OSL_ENSURE( xSupbook , "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
1830         if( xSupbook )
1831             xSupbook->StoreCellRange( rRange, rSBIndex.mnSBTab );
1832     }
1833 }
1834 
1835 namespace {
1836 
1837 class FindSBIndexEntry
1838 {
1839 public:
FindSBIndexEntry(sal_uInt16 nSupbookId,sal_uInt16 nTabId)1840     explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) :
1841         mnSupbookId(nSupbookId), mnTabId(nTabId) {}
1842 
operator ()(const XclExpSupbookBuffer::XclExpSBIndex & r) const1843     bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const
1844     {
1845         return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab;
1846     }
1847 
1848 private:
1849     sal_uInt16 mnSupbookId;
1850     sal_uInt16 mnTabId;
1851 };
1852 
1853 }
1854 
StoreCell(sal_uInt16 nFileId,const OUString & rTabName,const ScAddress & rCell)1855 void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell )
1856 {
1857     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
1858     const OUString* pUrl = pRefMgr->getExternalFileName(nFileId);
1859     if (!pUrl)
1860         return;
1861 
1862     XclExpSupbookRef xSupbook;
1863     sal_uInt16 nSupbookId;
1864     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
1865     {
1866         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
1867         nSupbookId = Append(xSupbook);
1868     }
1869 
1870     sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
1871     if (nSheetId == EXC_NOTAB)
1872         // specified table name not found in this SUPBOOK.
1873         return;
1874 
1875     FindSBIndexEntry f(nSupbookId, nSheetId);
1876     if (::std::none_of(maSBIndexVec.begin(), maSBIndexVec.end(), f))
1877     {
1878         maSBIndexVec.emplace_back();
1879         XclExpSBIndex& r = maSBIndexVec.back();
1880         r.mnSupbook = nSupbookId;
1881         r.mnSBTab   = nSheetId;
1882     }
1883 
1884     xSupbook->StoreCell_(nSheetId, rCell);
1885 }
1886 
StoreCellRange(sal_uInt16 nFileId,const OUString & rTabName,const ScRange & rRange)1887 void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange )
1888 {
1889     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
1890     const OUString* pUrl = pRefMgr->getExternalFileName(nFileId);
1891     if (!pUrl)
1892         return;
1893 
1894     XclExpSupbookRef xSupbook;
1895     sal_uInt16 nSupbookId;
1896     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
1897     {
1898         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
1899         nSupbookId = Append(xSupbook);
1900     }
1901 
1902     SCTAB nTabCount = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
1903 
1904     // If this is a multi-table range, get token for each table.
1905     using namespace ::formula;
1906     SCTAB aMatrixListSize = 0;
1907 
1908     // This is a new'ed instance, so we must manage its life cycle here.
1909     ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, nullptr);
1910     if (!pArray.get())
1911         return;
1912 
1913     FormulaTokenArrayPlainIterator aIter(*pArray);
1914     for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
1915     {
1916         if (p->GetType() == svMatrix)
1917             ++aMatrixListSize;
1918         else if (p->GetOpCode() != ocSep)
1919         {
1920             // This is supposed to be ocSep!!!
1921             return;
1922         }
1923     }
1924 
1925     if (aMatrixListSize != nTabCount)
1926     {
1927         // matrix size mismatch!
1928         return;
1929     }
1930 
1931     sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
1932 
1933     ScRange aRange(rRange);
1934     aRange.aStart.SetTab(0);
1935     aRange.aEnd.SetTab(0);
1936     for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
1937     {
1938         sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab);
1939         FindSBIndexEntry f(nSupbookId, nSheetId);
1940         if (::std::none_of(maSBIndexVec.begin(), maSBIndexVec.end(), f))
1941         {
1942             maSBIndexVec.emplace_back();
1943             XclExpSBIndex& r = maSBIndexVec.back();
1944             r.mnSupbook = nSupbookId;
1945             r.mnSBTab   = nSheetId;
1946         }
1947 
1948         xSupbook->StoreCellRange_(nSheetId, aRange);
1949     }
1950 }
1951 
InsertAddIn(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const OUString & rName)1952 bool XclExpSupbookBuffer::InsertAddIn(
1953         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const OUString& rName )
1954 {
1955     XclExpSupbookRef xSupbook;
1956     if( mnAddInSB == SAL_MAX_UINT16 )
1957     {
1958         xSupbook.reset( new XclExpSupbook( GetRoot() ) );
1959         mnAddInSB = Append( xSupbook );
1960     }
1961     else
1962         xSupbook = maSupbookList.GetRecord( mnAddInSB );
1963     OSL_ENSURE( xSupbook, "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
1964     rnSupbook = mnAddInSB;
1965     rnExtName = xSupbook->InsertAddIn( rName );
1966     return rnExtName > 0;
1967 }
1968 
InsertEuroTool(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const OUString & rName)1969 bool XclExpSupbookBuffer::InsertEuroTool(
1970         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const OUString& rName )
1971 {
1972     XclExpSupbookRef xSupbook;
1973     OUString aUrl( "\001\010EUROTOOL.XLA" );
1974     if( !GetSupbookUrl( xSupbook, rnSupbook, aUrl ) )
1975     {
1976         xSupbook.reset( new XclExpSupbook( GetRoot(), aUrl, XclSupbookType::Eurotool ) );
1977         rnSupbook = Append( xSupbook );
1978     }
1979     rnExtName = xSupbook->InsertEuroTool( rName );
1980     return rnExtName > 0;
1981 }
1982 
InsertDde(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const OUString & rApplic,const OUString & rTopic,const OUString & rItem)1983 bool XclExpSupbookBuffer::InsertDde(
1984         sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
1985         const OUString& rApplic, const OUString& rTopic, const OUString& rItem )
1986 {
1987     XclExpSupbookRef xSupbook;
1988     if( !GetSupbookDde( xSupbook, rnSupbook, rApplic, rTopic ) )
1989     {
1990         xSupbook.reset( new XclExpSupbook( GetRoot(), rApplic, rTopic ) );
1991         rnSupbook = Append( xSupbook );
1992     }
1993     rnExtName = xSupbook->InsertDde( rItem );
1994     return rnExtName > 0;
1995 }
1996 
InsertExtName(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const OUString & rUrl,const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)1997 bool XclExpSupbookBuffer::InsertExtName(
1998         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const OUString& rUrl,
1999         const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray )
2000 {
2001     XclExpSupbookRef xSupbook;
2002     if (!GetSupbookUrl(xSupbook, rnSupbook, rUrl))
2003     {
2004         xSupbook.reset( new XclExpSupbook(GetRoot(), rUrl) );
2005         rnSupbook = Append(xSupbook);
2006     }
2007     rnExtName = xSupbook->InsertExtName(rName, rArray);
2008     return rnExtName > 0;
2009 }
2010 
GetXti(sal_uInt16 nFileId,const OUString & rTabName,sal_uInt16 nXclTabSpan,XclExpRefLogEntry * pRefLogEntry)2011 XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
2012                                        XclExpRefLogEntry* pRefLogEntry )
2013 {
2014     XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB);
2015     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
2016     const OUString* pUrl = pRefMgr->getExternalFileName(nFileId);
2017     if (!pUrl)
2018         return aXti;
2019 
2020     XclExpSupbookRef xSupbook;
2021     sal_uInt16 nSupbookId;
2022     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
2023     {
2024         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
2025         nSupbookId = Append(xSupbook);
2026     }
2027     aXti.mnSupbook = nSupbookId;
2028 
2029     sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
2030     if (nFirstSheetId == EXC_NOTAB)
2031     {
2032         // first sheet not found in SUPBOOK.
2033         return aXti;
2034     }
2035     sal_uInt16 nSheetCount = xSupbook->GetTabCount();
2036     for (sal_uInt16 i = 0; i < nXclTabSpan; ++i)
2037     {
2038         sal_uInt16 nSheetId = nFirstSheetId + i;
2039         if (nSheetId >= nSheetCount)
2040             return aXti;
2041 
2042         FindSBIndexEntry f(nSupbookId, nSheetId);
2043         if (::std::none_of(maSBIndexVec.begin(), maSBIndexVec.end(), f))
2044         {
2045             maSBIndexVec.emplace_back();
2046             XclExpSBIndex& r = maSBIndexVec.back();
2047             r.mnSupbook = nSupbookId;
2048             r.mnSBTab   = nSheetId;
2049         }
2050         if (i == 0)
2051             aXti.mnFirstSBTab = nSheetId;
2052         if (i == nXclTabSpan - 1)
2053             aXti.mnLastSBTab = nSheetId;
2054     }
2055 
2056     if (pRefLogEntry)
2057     {
2058         pRefLogEntry->mnFirstXclTab = 0;
2059         pRefLogEntry->mnLastXclTab  = 0;
2060         if (xSupbook)
2061             xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
2062     }
2063 
2064     return aXti;
2065 }
2066 
Save(XclExpStream & rStrm)2067 void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
2068 {
2069     maSupbookList.Save( rStrm );
2070 }
2071 
SaveXml(XclExpXmlStream & rStrm)2072 void XclExpSupbookBuffer::SaveXml( XclExpXmlStream& rStrm )
2073 {
2074     ::std::map< sal_uInt16, OUString > aMap;
2075     for (size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos)
2076     {
2077         XclExpSupbookRef xRef( maSupbookList.GetRecord( nPos));
2078         if (xRef->GetType() != XclSupbookType::Extern)
2079             continue;   // handle only external reference (for now?)
2080 
2081         sal_uInt16 nId = xRef->GetFileId();
2082         const OUString& rUrl = xRef->GetUrl();
2083         ::std::pair< ::std::map< sal_uInt16, OUString >::iterator, bool > aInsert(
2084                 aMap.insert( ::std::make_pair( nId, rUrl)));
2085         if (!aInsert.second)
2086         {
2087             SAL_WARN( "sc.filter", "XclExpSupbookBuffer::SaveXml: file ID already used: " << nId <<
2088                     " wanted for " << rUrl << " and is " << (*aInsert.first).second <<
2089                     (rUrl == (*aInsert.first).second ? " multiple Supbook not supported" : ""));
2090             continue;
2091         }
2092 
2093         OUString sId;
2094         sax_fastparser::FSHelperPtr pExternalLink = rStrm.CreateOutputStream(
2095                 XclXmlUtils::GetStreamName( "xl/", "externalLinks/externalLink", nId),
2096                 XclXmlUtils::GetStreamName( nullptr, "externalLinks/externalLink", nId),
2097                 rStrm.GetCurrentStream()->getOutputStream(),
2098                 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
2099                 CREATE_OFFICEDOC_RELATION_TYPE("externalLink"),
2100                 &sId );
2101 
2102         // externalReference entry in workbook externalReferences
2103         rStrm.GetCurrentStream()->singleElement( XML_externalReference,
2104                 FSNS(XML_r, XML_id), sId.toUtf8() );
2105 
2106         // Each externalBook in a separate stream.
2107         rStrm.PushStream( pExternalLink );
2108         xRef->SaveXml( rStrm );
2109         rStrm.PopStream();
2110     }
2111 }
2112 
HasExternalReferences() const2113 bool XclExpSupbookBuffer::HasExternalReferences() const
2114 {
2115     for (size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos)
2116     {
2117         if (maSupbookList.GetRecord( nPos)->GetType() == XclSupbookType::Extern)
2118             return true;
2119     }
2120     return false;
2121 }
2122 
GetSupbookUrl(XclExpSupbookRef & rxSupbook,sal_uInt16 & rnIndex,const OUString & rUrl) const2123 bool XclExpSupbookBuffer::GetSupbookUrl(
2124         XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex, const OUString& rUrl ) const
2125 {
2126     for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
2127     {
2128         rxSupbook = maSupbookList.GetRecord( nPos );
2129         if( rxSupbook->IsUrlLink( rUrl ) )
2130         {
2131             rnIndex = ulimit_cast< sal_uInt16 >( nPos );
2132             return true;
2133         }
2134     }
2135     return false;
2136 }
2137 
GetSupbookDde(XclExpSupbookRef & rxSupbook,sal_uInt16 & rnIndex,const OUString & rApplic,const OUString & rTopic) const2138 bool XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef& rxSupbook,
2139         sal_uInt16& rnIndex, const OUString& rApplic, const OUString& rTopic ) const
2140 {
2141     for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
2142     {
2143         rxSupbook = maSupbookList.GetRecord( nPos );
2144         if( rxSupbook->IsDdeLink( rApplic, rTopic ) )
2145         {
2146             rnIndex = ulimit_cast< sal_uInt16 >( nPos );
2147             return true;
2148         }
2149     }
2150     return false;
2151 }
2152 
Append(XclExpSupbookRef const & xSupbook)2153 sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef const & xSupbook )
2154 {
2155     maSupbookList.AppendRecord( xSupbook );
2156     return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
2157 }
2158 
2159 // Export link manager ========================================================
2160 
XclExpLinkManagerImpl(const XclExpRoot & rRoot)2161 XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
2162     XclExpRoot( rRoot )
2163 {
2164 }
2165 
XclExpLinkManagerImpl5(const XclExpRoot & rRoot)2166 XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot& rRoot ) :
2167     XclExpLinkManagerImpl( rRoot )
2168 {
2169 }
2170 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)2171 void XclExpLinkManagerImpl5::FindExtSheet(
2172         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
2173         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
2174 {
2175     FindInternal( rnExtSheet, rnFirstXclTab, nFirstScTab );
2176     if( (rnFirstXclTab == EXC_TAB_DELETED) || (nFirstScTab == nLastScTab) )
2177     {
2178         rnLastXclTab = rnFirstXclTab;
2179     }
2180     else
2181     {
2182         sal_uInt16 nDummyExtSheet;
2183         FindInternal( nDummyExtSheet, rnLastXclTab, nLastScTab );
2184     }
2185 
2186     OSL_ENSURE( !pRefLogEntry, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
2187 }
2188 
FindExtSheet(sal_Unicode cCode)2189 sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
2190 {
2191     sal_uInt16 nExtSheet;
2192     FindInternal( nExtSheet, cCode );
2193     return nExtSheet;
2194 }
2195 
FindExtSheet(sal_uInt16,const OUString &,sal_uInt16,sal_uInt16 &,sal_uInt16 &,sal_uInt16 &,XclExpRefLogEntry *)2196 void XclExpLinkManagerImpl5::FindExtSheet(
2197     sal_uInt16 /*nFileId*/, const OUString& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/,
2198     sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/,
2199     XclExpRefLogEntry* /*pRefLogEntry*/ )
2200 {
2201     // not implemented
2202 }
2203 
StoreCellRange(const ScSingleRefData &,const ScSingleRefData &,const ScAddress &)2204 void XclExpLinkManagerImpl5::StoreCellRange( const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/, const ScAddress& /*rPos*/ )
2205 {
2206     // not implemented
2207 }
2208 
StoreCell(sal_uInt16,const OUString &,const ScAddress &)2209 void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const OUString& /*rTabName*/, const ScAddress& /*rPos*/ )
2210 {
2211     // not implemented
2212 }
2213 
StoreCellRange(sal_uInt16,const OUString &,const ScRange &)2214 void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const OUString& /*rTabName*/, const ScRange& /*rRange*/ )
2215 {
2216     // not implemented
2217 }
2218 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rName)2219 bool XclExpLinkManagerImpl5::InsertAddIn(
2220         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rName )
2221 {
2222     XclExpExtSheetRef xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_ADDIN );
2223     if( xExtSheet )
2224     {
2225         rnExtName = xExtSheet->InsertAddIn( rName );
2226         return rnExtName > 0;
2227     }
2228     return false;
2229 }
2230 
InsertEuroTool(sal_uInt16 &,sal_uInt16 &,const OUString &)2231 bool XclExpLinkManagerImpl5::InsertEuroTool(
2232          sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const OUString& /*rName*/ )
2233 {
2234      return false;
2235 }
2236 
InsertDde(sal_uInt16 &,sal_uInt16 &,const OUString &,const OUString &,const OUString &)2237 bool XclExpLinkManagerImpl5::InsertDde(
2238         sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/,
2239         const OUString& /*rApplic*/, const OUString& /*rTopic*/, const OUString& /*rItem*/ )
2240 {
2241     // not implemented
2242     return false;
2243 }
2244 
InsertExtName(sal_uInt16 &,sal_uInt16 &,const OUString &,const OUString &,const ScExternalRefCache::TokenArrayRef &)2245 bool XclExpLinkManagerImpl5::InsertExtName(
2246         sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const OUString& /*rUrl*/,
2247         const OUString& /*rName*/, const ScExternalRefCache::TokenArrayRef& /*rArray*/ )
2248 {
2249     // not implemented
2250     return false;
2251 }
2252 
Save(XclExpStream & rStrm)2253 void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
2254 {
2255     if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
2256     {
2257         // EXTERNCOUNT record
2258         XclExpUInt16Record( EXC_ID_EXTERNCOUNT, nExtSheetCount ).Save( rStrm );
2259         // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
2260         maExtSheetList.Save( rStrm );
2261     }
2262 }
2263 
SaveXml(XclExpXmlStream &)2264 void XclExpLinkManagerImpl5::SaveXml( XclExpXmlStream& /*rStrm*/ )
2265 {
2266     // not applicable
2267 }
2268 
GetExtSheetCount() const2269 sal_uInt16 XclExpLinkManagerImpl5::GetExtSheetCount() const
2270 {
2271     return static_cast< sal_uInt16 >( maExtSheetList.GetSize() );
2272 }
2273 
AppendInternal(XclExpExtSheetRef const & xExtSheet)2274 sal_uInt16 XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef const & xExtSheet )
2275 {
2276     if( GetExtSheetCount() < 0x7FFF )
2277     {
2278         maExtSheetList.AppendRecord( xExtSheet );
2279         // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
2280         return static_cast< sal_uInt16 >( -GetExtSheetCount() );
2281     }
2282     return 0;
2283 }
2284 
CreateInternal()2285 void XclExpLinkManagerImpl5::CreateInternal()
2286 {
2287     if( maIntTabMap.empty() )
2288     {
2289         // create EXTERNSHEET records for all internal exported sheets
2290         XclExpTabInfo& rTabInfo = GetTabInfo();
2291         for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
2292         {
2293             if( rTabInfo.IsExportTab( nScTab ) )
2294             {
2295                 XclExpExtSheetRef xRec;
2296                 if( nScTab == GetCurrScTab() )
2297                     xRec.reset( new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB ) );
2298                 else
2299                     xRec.reset( new XclExpExternSheet( GetRoot(), rTabInfo.GetScTabName( nScTab ) ) );
2300                 maIntTabMap[ nScTab ] = AppendInternal( xRec );
2301             }
2302         }
2303     }
2304 }
2305 
GetInternal(sal_uInt16 nExtSheet)2306 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet )
2307 {
2308     return maExtSheetList.GetRecord( static_cast< sal_uInt16 >( -nExtSheet - 1 ) );
2309 }
2310 
FindInternal(sal_uInt16 & rnExtSheet,sal_uInt16 & rnXclTab,SCTAB nScTab)2311 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
2312         sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab )
2313 {
2314     // create internal EXTERNSHEET records on demand
2315     CreateInternal();
2316 
2317     // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
2318     XclExpExtSheetRef xExtSheet;
2319     XclExpIntTabMap::const_iterator aIt = maIntTabMap.find( nScTab );
2320     if( aIt == maIntTabMap.end() )
2321     {
2322         xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_OWNDOC );
2323         rnXclTab = EXC_TAB_DELETED;
2324     }
2325     else
2326     {
2327         rnExtSheet = aIt->second;
2328         xExtSheet = GetInternal( rnExtSheet );
2329         rnXclTab = GetTabInfo().GetXclTab( nScTab );
2330     }
2331     return xExtSheet;
2332 }
2333 
FindInternal(sal_uInt16 & rnExtSheet,sal_Unicode cCode)2334 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
2335     sal_uInt16& rnExtSheet, sal_Unicode cCode )
2336 {
2337     XclExpExtSheetRef xExtSheet;
2338     XclExpCodeMap::const_iterator aIt = maCodeMap.find( cCode );
2339     if( aIt == maCodeMap.end() )
2340     {
2341         xExtSheet.reset( new XclExpExternSheet( GetRoot(), cCode ) );
2342         rnExtSheet = maCodeMap[ cCode ] = AppendInternal( xExtSheet );
2343     }
2344     else
2345     {
2346         rnExtSheet = aIt->second;
2347         xExtSheet = GetInternal( rnExtSheet );
2348     }
2349     return xExtSheet;
2350 }
2351 
XclExpLinkManagerImpl8(const XclExpRoot & rRoot)2352 XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot& rRoot ) :
2353     XclExpLinkManagerImpl( rRoot ),
2354     maSBBuffer( rRoot )
2355 {
2356 }
2357 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)2358 void XclExpLinkManagerImpl8::FindExtSheet(
2359         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
2360         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
2361 {
2362     XclExpTabInfo& rTabInfo = GetTabInfo();
2363     rnFirstXclTab = rTabInfo.GetXclTab( nFirstScTab );
2364     rnLastXclTab = rTabInfo.GetXclTab( nLastScTab );
2365     rnExtSheet = InsertXti( maSBBuffer.GetXti( rnFirstXclTab, rnLastXclTab, pRefLogEntry ) );
2366 }
2367 
FindExtSheet(sal_Unicode cCode)2368 sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
2369 {
2370     OSL_ENSURE( (cCode == EXC_EXTSH_OWNDOC) || (cCode == EXC_EXTSH_ADDIN),
2371         "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
2372     return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2373 }
2374 
FindExtSheet(sal_uInt16 nFileId,const OUString & rTabName,sal_uInt16 nXclTabSpan,sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstSBTab,sal_uInt16 & rnLastSBTab,XclExpRefLogEntry * pRefLogEntry)2375 void XclExpLinkManagerImpl8::FindExtSheet(
2376     sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
2377     sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
2378     XclExpRefLogEntry* pRefLogEntry )
2379 {
2380     XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, pRefLogEntry);
2381     rnExtSheet = InsertXti(aXti);
2382     rnFirstSBTab = aXti.mnFirstSBTab;
2383     rnLastSBTab  = aXti.mnLastSBTab;
2384 }
2385 
StoreCellRange(const ScSingleRefData & rRef1,const ScSingleRefData & rRef2,const ScAddress & rPos)2386 void XclExpLinkManagerImpl8::StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2, const ScAddress& rPos )
2387 {
2388     ScAddress aAbs1 = rRef1.toAbs(rPos);
2389     ScAddress aAbs2 = rRef2.toAbs(rPos);
2390     if (!rRef1.IsDeleted() && !rRef2.IsDeleted() && (aAbs1.Tab() >= 0) && (aAbs2.Tab() >= 0))
2391     {
2392         const XclExpTabInfo& rTabInfo = GetTabInfo();
2393         SCTAB nFirstScTab = aAbs1.Tab();
2394         SCTAB nLastScTab = aAbs2.Tab();
2395         ScRange aRange(aAbs1.Col(), aAbs1.Row(), 0, aAbs2.Col(), aAbs2.Row(), 0);
2396         for (SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab)
2397         {
2398             if( rTabInfo.IsExternalTab( nScTab ) )
2399             {
2400                 aRange.aStart.SetTab( nScTab );
2401                 aRange.aEnd.SetTab( nScTab );
2402                 maSBBuffer.StoreCellRange( aRange );
2403             }
2404         }
2405     }
2406 }
2407 
StoreCell(sal_uInt16 nFileId,const OUString & rTabName,const ScAddress & rPos)2408 void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rPos )
2409 {
2410     maSBBuffer.StoreCell(nFileId, rTabName, rPos);
2411 }
2412 
StoreCellRange(sal_uInt16 nFileId,const OUString & rTabName,const ScRange & rRange)2413 void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange )
2414 {
2415     maSBBuffer.StoreCellRange(nFileId, rTabName, rRange);
2416 }
2417 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rName)2418 bool XclExpLinkManagerImpl8::InsertAddIn(
2419         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rName )
2420 {
2421     sal_uInt16 nSupbook;
2422     if( maSBBuffer.InsertAddIn( nSupbook, rnExtName, rName ) )
2423     {
2424         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2425         return true;
2426     }
2427     return false;
2428 }
2429 
InsertEuroTool(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rName)2430 bool XclExpLinkManagerImpl8::InsertEuroTool(
2431          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rName )
2432 {
2433     sal_uInt16 nSupbook;
2434     if( maSBBuffer.InsertEuroTool( nSupbook, rnExtName, rName ) )
2435     {
2436         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2437         return true;
2438     }
2439     return false;
2440 }
2441 
InsertDde(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rApplic,const OUString & rTopic,const OUString & rItem)2442 bool XclExpLinkManagerImpl8::InsertDde(
2443         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2444         const OUString& rApplic, const OUString& rTopic, const OUString& rItem )
2445 {
2446     sal_uInt16 nSupbook;
2447     if( maSBBuffer.InsertDde( nSupbook, rnExtName, rApplic, rTopic, rItem ) )
2448     {
2449         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2450         return true;
2451     }
2452     return false;
2453 }
2454 
InsertExtName(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rUrl,const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)2455 bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2456         const OUString& rUrl, const OUString& rName, const ScExternalRefCache::TokenArrayRef& rArray )
2457 {
2458     sal_uInt16 nSupbook;
2459     if( maSBBuffer.InsertExtName( nSupbook, rnExtName, rUrl, rName, rArray ) )
2460     {
2461         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2462         return true;
2463     }
2464     return false;
2465 }
2466 
Save(XclExpStream & rStrm)2467 void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
2468 {
2469     if( !maXtiVec.empty() )
2470     {
2471         // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
2472         maSBBuffer.Save( rStrm );
2473 
2474         // EXTERNSHEET
2475         sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXtiVec.size() );
2476         rStrm.StartRecord( EXC_ID_EXTERNSHEET, 2 + 6 * nCount );
2477         rStrm << nCount;
2478         rStrm.SetSliceSize( 6 );
2479         for( const auto& rXti : maXtiVec )
2480             rXti.Save( rStrm );
2481         rStrm.EndRecord();
2482     }
2483 }
2484 
SaveXml(XclExpXmlStream & rStrm)2485 void XclExpLinkManagerImpl8::SaveXml( XclExpXmlStream& rStrm )
2486 {
2487     if (maSBBuffer.HasExternalReferences())
2488     {
2489         sax_fastparser::FSHelperPtr pWorkbook = rStrm.GetCurrentStream();
2490         pWorkbook->startElement(XML_externalReferences);
2491 
2492         // externalLink, externalBook, sheetNames, sheetDataSet, externalName
2493         maSBBuffer.SaveXml( rStrm );
2494 
2495         pWorkbook->endElement( XML_externalReferences);
2496     }
2497 
2498     // TODO: equivalent for EXTERNSHEET in OOXML?
2499 #if 0
2500     if( !maXtiVec.empty() )
2501     {
2502         for( const auto& rXti : maXtiVec )
2503             rXti.SaveXml( rStrm );
2504     }
2505 #endif
2506 }
2507 
InsertXti(const XclExpXti & rXti)2508 sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
2509 {
2510     auto aIt = std::find(maXtiVec.begin(), maXtiVec.end(), rXti);
2511     if (aIt != maXtiVec.end())
2512         return ulimit_cast< sal_uInt16 >( std::distance(maXtiVec.begin(), aIt) );
2513     maXtiVec.push_back( rXti );
2514     return ulimit_cast< sal_uInt16 >( maXtiVec.size() - 1 );
2515 }
2516 
XclExpLinkManager(const XclExpRoot & rRoot)2517 XclExpLinkManager::XclExpLinkManager( const XclExpRoot& rRoot ) :
2518     XclExpRoot( rRoot )
2519 {
2520     switch( GetBiff() )
2521     {
2522         case EXC_BIFF5:
2523             mxImpl.reset( new XclExpLinkManagerImpl5( rRoot ) );
2524         break;
2525         case EXC_BIFF8:
2526             mxImpl.reset( new XclExpLinkManagerImpl8( rRoot ) );
2527         break;
2528         default:
2529             DBG_ERROR_BIFF();
2530     }
2531 }
2532 
~XclExpLinkManager()2533 XclExpLinkManager::~XclExpLinkManager()
2534 {
2535 }
2536 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnXclTab,SCTAB nScTab,XclExpRefLogEntry * pRefLogEntry)2537 void XclExpLinkManager::FindExtSheet(
2538         sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab,
2539         SCTAB nScTab, XclExpRefLogEntry* pRefLogEntry )
2540 {
2541     mxImpl->FindExtSheet( rnExtSheet, rnXclTab, rnXclTab, nScTab, nScTab, pRefLogEntry );
2542 }
2543 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)2544 void XclExpLinkManager::FindExtSheet(
2545         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
2546         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
2547 {
2548     mxImpl->FindExtSheet( rnExtSheet, rnFirstXclTab, rnLastXclTab, nFirstScTab, nLastScTab, pRefLogEntry );
2549 }
2550 
FindExtSheet(sal_Unicode cCode)2551 sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
2552 {
2553     return mxImpl->FindExtSheet( cCode );
2554 }
2555 
FindExtSheet(sal_uInt16 nFileId,const OUString & rTabName,sal_uInt16 nXclTabSpan,sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstSBTab,sal_uInt16 & rnLastSBTab,XclExpRefLogEntry * pRefLogEntry)2556 void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const OUString& rTabName, sal_uInt16 nXclTabSpan,
2557                                       sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
2558                                       XclExpRefLogEntry* pRefLogEntry )
2559 {
2560     mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry );
2561 }
2562 
StoreCell(const ScSingleRefData & rRef,const ScAddress & rPos)2563 void XclExpLinkManager::StoreCell( const ScSingleRefData& rRef, const ScAddress& rPos )
2564 {
2565     mxImpl->StoreCellRange(rRef, rRef, rPos);
2566 }
2567 
StoreCellRange(const ScComplexRefData & rRef,const ScAddress & rPos)2568 void XclExpLinkManager::StoreCellRange( const ScComplexRefData& rRef, const ScAddress& rPos )
2569 {
2570     mxImpl->StoreCellRange(rRef.Ref1, rRef.Ref2, rPos);
2571 }
2572 
StoreCell(sal_uInt16 nFileId,const OUString & rTabName,const ScAddress & rPos)2573 void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rPos )
2574 {
2575     mxImpl->StoreCell(nFileId, rTabName, rPos);
2576 }
2577 
StoreCellRange(sal_uInt16 nFileId,const OUString & rTabName,const ScRange & rRange)2578 void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange )
2579 {
2580     mxImpl->StoreCellRange(nFileId, rTabName, rRange);
2581 }
2582 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rName)2583 bool XclExpLinkManager::InsertAddIn(
2584         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rName )
2585 {
2586     return mxImpl->InsertAddIn( rnExtSheet, rnExtName, rName );
2587 }
2588 
InsertEuroTool(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rName)2589 bool XclExpLinkManager::InsertEuroTool(
2590         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rName )
2591 {
2592     return mxImpl->InsertEuroTool( rnExtSheet, rnExtName, rName );
2593 }
2594 
InsertDde(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rApplic,const OUString & rTopic,const OUString & rItem)2595 bool XclExpLinkManager::InsertDde(
2596         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2597         const OUString& rApplic, const OUString& rTopic, const OUString& rItem )
2598 {
2599     return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
2600 }
2601 
InsertExtName(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const OUString & rUrl,const OUString & rName,const ScExternalRefCache::TokenArrayRef & rArray)2602 bool XclExpLinkManager::InsertExtName(
2603     sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const OUString& rUrl, const OUString& rName,
2604     const ScExternalRefCache::TokenArrayRef& rArray )
2605 {
2606     return mxImpl->InsertExtName(rnExtSheet, rnExtName, rUrl, rName, rArray);
2607 }
2608 
Save(XclExpStream & rStrm)2609 void XclExpLinkManager::Save( XclExpStream& rStrm )
2610 {
2611     mxImpl->Save( rStrm );
2612 }
2613 
SaveXml(XclExpXmlStream & rStrm)2614 void XclExpLinkManager::SaveXml( XclExpXmlStream& rStrm )
2615 {
2616     mxImpl->SaveXml( rStrm );
2617 }
2618 
2619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2620