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