xref: /trunk/main/sc/source/filter/excel/xelink.cxx (revision b77af630)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scfilt.hxx"
26 #include "xelink.hxx"
27 
28 #include <algorithm>
29 #include <unotools/collatorwrapper.hxx>
30 #include <svl/zforlist.hxx>
31 #include "document.hxx"
32 #include "cell.hxx"
33 #include "scextopt.hxx"
34 #include "externalrefmgr.hxx"
35 
36 #include <vector>
37 #include <memory>
38 
39 using ::std::auto_ptr;
40 using ::std::find_if;
41 using ::std::vector;
42 using ::rtl::OUString;
43 using ::com::sun::star::uno::Any;
44 
45 // ============================================================================
46 // *** Helper classes ***
47 // ============================================================================
48 
49 // External names =============================================================
50 
51 /** This is a base class for any external name (i.e. add-in names or DDE links).
52     @descr  Derived classes implement creation and export of the external names. */
53 class XclExpExtNameBase : public XclExpRecord, protected XclExpRoot
54 {
55 public:
56     /** @param nFlags  The flags to export. */
57     explicit            XclExpExtNameBase( const XclExpRoot& rRoot,
58                             const String& rName, sal_uInt16 nFlags = 0 );
59     virtual             ~XclExpExtNameBase();
60 
61     /** Returns the name string of the external name. */
GetName() const62     inline const String& 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 );
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 private:
72     String              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 // ----------------------------------------------------------------------------
78 
79 /** Represents an EXTERNNAME record for an add-in function name. */
80 class XclExpExtNameAddIn : public XclExpExtNameBase
81 {
82 public:
83     explicit            XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName );
84 
85 private:
86     /** Writes additional record contents. */
87     virtual void        WriteAddData( XclExpStream& rStrm );
88 };
89 
90 // ----------------------------------------------------------------------------
91 
92 /** Represents an EXTERNNAME record for a DDE link. */
93 class XclExpExtNameDde : public XclExpExtNameBase
94 {
95 public:
96     explicit            XclExpExtNameDde( const XclExpRoot& rRoot, const String& rName,
97                             sal_uInt16 nFlags, const ScMatrix* pResults = 0 );
98 
99 private:
100     /** Writes additional record contents. */
101     virtual void        WriteAddData( XclExpStream& rStrm );
102 
103 private:
104     typedef ScfRef< XclExpCachedMatrix > XclExpCachedMatRef;
105     XclExpCachedMatRef  mxMatrix;       /// Cached results of the DDE link.
106 };
107 
108 // ----------------------------------------------------------------------------
109 
110 class XclExpSupbook;
111 
112 class XclExpExtName : public XclExpExtNameBase
113 {
114 public:
115     explicit            XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const String& rName,
116                                        const ScExternalRefCache::TokenArrayRef pArray );
117 
118 private:
119     /** Writes additional record contents. */
120     virtual void        WriteAddData( XclExpStream& rStrm );
121 
122 private:
123     const XclExpSupbook&    mrSupbook;
124     auto_ptr<ScTokenArray>  mpArray;
125 };
126 
127 // List of external names =====================================================
128 
129 /** List of all external names of a sheet. */
130 class XclExpExtNameBuffer : public XclExpRecordBase, protected XclExpRoot
131 {
132 public:
133     explicit            XclExpExtNameBuffer( const XclExpRoot& rRoot );
134 
135     /** Inserts an add-in function name
136         @return  The 1-based (Excel-like) list index of the name. */
137     sal_uInt16          InsertAddIn( const String& rName );
138     /** InsertEuroTool */
139     sal_uInt16          InsertEuroTool( const String& rName );
140     /** Inserts a DDE link.
141         @return  The 1-based (Excel-like) list index of the DDE link. */
142     sal_uInt16          InsertDde( const String& rApplic, const String& rTopic, const String& rItem );
143 
144     sal_uInt16          InsertExtName( const XclExpSupbook& rSupbook, const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
145 
146     /** Writes the EXTERNNAME record list. */
147     virtual void        Save( XclExpStream& rStrm );
148 
149 private:
150     typedef XclExpRecordList< XclExpExtNameBase >   XclExpExtNameList;
151     typedef XclExpExtNameList::RecordRefType        XclExpExtNameRef;
152 
153 private:
154     /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
155     sal_uInt16          GetIndex( const String& rName ) const;
156     /** Appends the passed newly crested external name.
157         @return  The 1-based (Excel-like) list index of the appended name. */
158     sal_uInt16          AppendNew( XclExpExtNameBase* pExtName );
159 
160 private:
161     XclExpExtNameList   maNameList;     /// The list with all EXTERNNAME records.
162 };
163 
164 // Cached external cells ======================================================
165 
166 /** Stores the contents of a consecutive row of external cells (record CRN). */
167 class XclExpCrn : public XclExpRecord
168 {
169 public:
170     explicit            XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue );
171 
172     /** Returns true, if the passed value could be appended to this record. */
173     bool                InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
174 
175 private:
176     virtual void        WriteBody( XclExpStream& rStrm );
177 
178     void                WriteBool( XclExpStream& rStrm, bool bValue );
179     void                WriteDouble( XclExpStream& rStrm, double fValue );
180     void                WriteString( XclExpStream& rStrm, const OUString& rValue );
181     void                WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode );
182     void                WriteEmpty( XclExpStream& rStrm );
183 
184 private:
185     typedef ::std::vector< Any > CachedValues;
186 
187     CachedValues        maValues;   /// All cached values.
188     SCCOL               mnScCol;    /// Column index of the first external cell.
189     SCROW               mnScRow;    /// Row index of the external cells.
190 };
191 
192 // ----------------------------------------------------------------------------
193 
194 /** Represents the record XCT which is the header record of a CRN record list.
195  */
196 class XclExpXct : public XclExpRecordBase, protected XclExpRoot
197 {
198 public:
199     explicit            XclExpXct( const XclExpRoot& rRoot,
200                             const String& rTabName, sal_uInt16 nSBTab,
201                             ScExternalRefCache::TableTypeRef xCacheTable );
202 
203     /** Returns the external sheet name. */
GetTabName() const204     inline const XclExpString& GetTabName() const { return maTabName; }
205 
206     /** Stores all cells in the given range in the CRN list. */
207     void                StoreCellRange( const ScRange& rRange );
208 
209     void                StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken );
210     void                StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken );
211 
212     /** Writes the XCT and all CRN records. */
213     virtual void        Save( XclExpStream& rStrm );
214 
215 private:
216     ScExternalRefCache::TableTypeRef mxCacheTable;
217     ScMarkData          maUsedCells;    /// Contains addresses of all stored cells.
218     ScRange             maBoundRange;   /// Bounding box of maUsedCells.
219     XclExpString        maTabName;      /// Sheet name of the external sheet.
220     sal_uInt16          mnSBTab;        /// Referred sheet index in SUPBOOK record.
221 };
222 
223 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
224 
225 /** Base class for records representing external sheets/documents.
226 
227     In BIFF5/BIFF7, this record is the EXTERNSHEET record containing one sheet
228     of the own or an external document. In BIFF8, this record is the SUPBOOK
229     record representing the entire own or external document with all referenced
230     sheets.
231  */
232 class XclExpExternSheetBase : public XclExpRecord, protected XclExpRoot
233 {
234 public:
235     explicit            XclExpExternSheetBase( const XclExpRoot& rRoot,
236                             sal_uInt16 nRecId, sal_uInt32 nRecSize = 0 );
237 
238 protected:
239     /** Creates and returns the list of EXTERNNAME records. */
240     XclExpExtNameBuffer& GetExtNameBuffer();
241     /** Creates and returns the list of EXTERNNAME records. */
242     void                WriteExtNameBuffer( XclExpStream& rStrm );
243 
244 private:
245     typedef ScfRef< XclExpExtNameBuffer >   XclExpExtNameBfrRef;
246     XclExpExtNameBfrRef mxExtNameBfr;   /// List of EXTERNNAME records.
247 };
248 
249 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
250 
251 /** Represents an EXTERNSHEET record containing the URL and sheet name of a sheet.
252     @descr  This class is used up to BIFF7 only, writing a BIFF8 EXTERNSHEET
253         record is implemented directly in the link manager. */
254 class XclExpExternSheet : public XclExpExternSheetBase
255 {
256 public:
257     /** Creates an EXTERNSHEET record containing a special code (i.e. own document or sheet). */
258     explicit            XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode );
259     /** Creates an EXTERNSHEET record referring to an internal sheet. */
260     explicit            XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName );
261 
262     /** Finds or inserts an EXTERNNAME record for add-ins.
263         @return  The 1-based EXTERNNAME record index; or 0, if the record list is full. */
264     sal_uInt16          InsertAddIn( const String& rName );
265 
266     /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
267     virtual void        Save( XclExpStream& rStrm );
268 
269 private:
270     /** Initializes the record data with the passed encoded URL. */
271     void                Init( const String& rEncUrl );
272     /** Writes the contents of the EXTERNSHEET  record. */
273     virtual void        WriteBody( XclExpStream& rStrm );
274 
275 private:
276     XclExpString        maTabName;      /// The name of the sheet.
277 };
278 
279 // External documents (SUPBOOK, BIFF8) ========================================
280 
281 /** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
282 class XclExpSupbook : public XclExpExternSheetBase
283 {
284 public:
285     /** Creates a SUPBOOK record for internal references. */
286     explicit            XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount );
287     /** Creates a SUPBOOK record for add-in functions. */
288     explicit            XclExpSupbook( const XclExpRoot& rRoot );
289     /** EUROTOOL SUPBOOK */
290     explicit            XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType );
291     /** Creates a SUPBOOK record for an external document. */
292     explicit            XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl );
293     /** Creates a SUPBOOK record for a DDE link. */
294     explicit            XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic );
295 
296     /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
297     bool                IsUrlLink( const String& rUrl ) const;
298     /** Returns true, if this SUPBOOK contains the passed DDE link. */
299     bool                IsDdeLink( const String& rApplic, const String& rTopic ) const;
300     /** Fills the passed reference log entry with the URL and sheet names. */
301     void                FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
302                             sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const;
303 
304     /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
305     void                StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab );
306 
307     void                StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ::formula::FormulaToken& rToken );
308     void                StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ::formula::FormulaToken& rToken );
309 
310     sal_uInt16          GetTabIndex( const String& rTabName ) const;
311     sal_uInt16          GetTabCount() const;
312 
313     /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
314     sal_uInt16          InsertTabName( const String& rTabName, ScExternalRefCache::TableTypeRef xCacheTable );
315     /** Finds or inserts an EXTERNNAME record for add-ins.
316         @return  The 1-based EXTERNNAME record index; or 0, if the record list is full. */
317     sal_uInt16          InsertAddIn( const String& rName );
318     /** InsertEuroTool */
319     sal_uInt16          InsertEuroTool( const String& rName );
320     /** Finds or inserts an EXTERNNAME record for DDE links.
321         @return  The 1-based EXTERNNAME record index; or 0, if the record list is full. */
322     sal_uInt16          InsertDde( const String& rItem );
323 
324     sal_uInt16          InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
325 
326     /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
327     virtual void        Save( XclExpStream& rStrm );
328 
329 private:
330     /** Returns the sheet name inside of this SUPBOOK. */
331     const XclExpString* GetTabName( sal_uInt16 nSBTab ) const;
332 
333     /** Writes the SUPBOOK record contents. */
334     virtual void        WriteBody( XclExpStream& rStrm );
335 
336 private:
337     typedef XclExpRecordList< XclExpXct >   XclExpXctList;
338     typedef XclExpXctList::RecordRefType    XclExpXctRef;
339 
340     XclExpXctList       maXctList;      /// List of XCT records (which contain CRN records).
341     String              maUrl;          /// URL of the external document or application name for DDE.
342     String              maDdeTopic;     /// Topic of an DDE link.
343     XclExpString        maUrlEncoded;   /// Document name encoded for Excel.
344     XclSupbookType      meType;         /// Type of this SUPBOOK record.
345     sal_uInt16          mnXclTabCount;  /// Number of internal sheets.
346 };
347 
348 // All SUPBOOKS in a document =================================================
349 
350 /** This struct contains a sheet index range for 3D references.
351     @descr  This reference consists of an index to a SUPBOOK record and indexes
352     to SUPBOOK sheet names. */
353 struct XclExpXti
354 {
355     sal_uInt16          mnSupbook;      /// Index to SUPBOOK record.
356     sal_uInt16          mnFirstSBTab;   /// Index to the first sheet of the range in the SUPBOOK.
357     sal_uInt16          mnLastSBTab;    /// Index to the last sheet of the range in the SUPBOOK.
358 
XclExpXtiXclExpXti359     inline explicit     XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
XclExpXtiXclExpXti360     inline explicit     XclExpXti( sal_uInt16 nSupbook, sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) :
361                             mnSupbook( nSupbook ), mnFirstSBTab( nFirstSBTab ), mnLastSBTab( nLastSBTab ) {}
362 
363     /** Writes this XTI structure (inside of the EXTERNSHEET record). */
SaveXclExpXti364     inline void         Save( XclExpStream& rStrm ) const
365                             { rStrm << mnSupbook << mnFirstSBTab << mnLastSBTab; }
366 };
367 
operator ==(const XclExpXti & rLeft,const XclExpXti & rRight)368 inline bool operator==( const XclExpXti& rLeft, const XclExpXti& rRight )
369 {
370     return
371         (rLeft.mnSupbook    == rRight.mnSupbook)    &&
372         (rLeft.mnFirstSBTab == rRight.mnFirstSBTab) &&
373         (rLeft.mnLastSBTab  == rRight.mnLastSBTab);
374 }
375 
376 // ----------------------------------------------------------------------------
377 
378 /** Contains a list of all SUPBOOK records and index arrays of external sheets. */
379 class XclExpSupbookBuffer : public XclExpRecordBase, protected XclExpRoot
380 {
381 public:
382     explicit            XclExpSupbookBuffer( const XclExpRoot& rRoot );
383 
384     /** Finds SUPBOOK index and SUPBOOK sheet range from given Excel sheet range.
385         @return  An XTI structure containing SUPBOOK and sheet indexes. */
386     XclExpXti           GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
387                             XclExpRefLogEntry* pRefLogEntry = 0 ) const;
388 
389     /** Stores all cells in the given range in a CRN record list. */
390     void                StoreCellRange( const ScRange& rRange );
391 
392     void                StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell );
393     void                StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange );
394 
395     /** Finds or inserts an EXTERNNAME record for an add-in function name.
396         @param rnSupbook  Returns the index of the SUPBOOK record which contains the add-in function name.
397         @param rnExtName  Returns the 1-based EXTERNNAME record index. */
398     bool                InsertAddIn(
399                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
400                             const String& rName );
401     /** InsertEuroTool */
402     bool                InsertEuroTool(
403                              sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
404                              const String& rName );
405     /** Finds or inserts an EXTERNNAME record for DDE links.
406         @param rnSupbook  Returns the index of the SUPBOOK record which contains the DDE link.
407         @param rnExtName  Returns the 1-based EXTERNNAME record index. */
408     bool                InsertDde(
409                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
410                             const String& rApplic, const String& rTopic, const String& rItem );
411 
412     bool                InsertExtName(
413                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
414                             const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
415 
416     XclExpXti           GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
417                                 XclExpRefLogEntry* pRefLogEntry = NULL );
418 
419     /** Writes all SUPBOOK records with their sub records. */
420     virtual void        Save( XclExpStream& rStrm );
421 
422     struct XclExpSBIndex
423     {
424         sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
425         sal_uInt16          mnSBTab;            /// Sheet name index in SUPBOOK for an Excel sheet.
SetXclExpSupbookBuffer::XclExpSBIndex426         inline void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
427                                 { mnSupbook = nSupbook; mnSBTab = nSBTab; }
428     };
429     typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
430 
431 private:
432     typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
433     typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
434 
435 private:
436     /** Searches for the SUPBOOK record containing the passed document URL.
437         @param rxSupbook  (out-param) Returns a reference to the SUPBOOK record, or 0.
438         @param rnIndex  (out-param) Returns the list index, if the SUPBOOK exists.
439         @return  True, if the SUPBOOK record exists (out-parameters are valid). */
440     bool                GetSupbookUrl( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
441                             const String& rUrl ) const;
442     /** Searches for the SUPBOOK record containing the passed DDE link.
443         @param rxSupbook  (out-param) Returns a reference to the SUPBOOK record, or 0.
444         @param rnIndex  (out-param) Returns the list index, if the SUPBOOK exists.
445         @return  True, if the SUPBOOK record exists (out-parameters are valid). */
446     bool                GetSupbookDde( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
447                             const String& rApplic, const String& rTopic ) const;
448 
449     /** Appends a new SUPBOOK to the list.
450         @return  The list index of the SUPBOOK record. */
451     sal_uInt16          Append( XclExpSupbookRef xSupbook );
452 
453 private:
454     XclExpSupbookList   maSupbookList;      /// List of all SUPBOOK records.
455     XclExpSBIndexVec    maSBIndexVec;       /// SUPBOOK and sheet name index for each Excel sheet.
456     sal_uInt16          mnOwnDocSB;         /// Index to SUPBOOK for own document.
457     sal_uInt16          mnAddInSB;          /// Index to add-in SUPBOOK.
458 };
459 
460 // Export link manager ========================================================
461 
462 /** Abstract base class for implementation classes of the link manager. */
463 class XclExpLinkManagerImpl : protected XclExpRoot
464 {
465 public:
466     /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
467     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
468                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
469                             SCTAB nFirstScTab, SCTAB nLastScTab,
470                             XclExpRefLogEntry* pRefLogEntry ) = 0;
471     /** Derived classes search for a special EXTERNSHEET index for the own document. */
472     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) = 0;
473 
474     virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
475                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
476                                XclExpRefLogEntry* pRefLogEntry ) = 0;
477 
478     /** Derived classes store all cells in the given range in a CRN record list. */
479     virtual void        StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 ) = 0;
480 
481     virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) = 0;
482     virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 ) = 0;
483 
484     /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
485     virtual bool        InsertAddIn(
486                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
487                             const String& rName ) = 0;
488     /** InsertEuroTool */
489     virtual bool        InsertEuroTool(
490                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
491                             const String& rName ) = 0;
492 
493     /** Derived classes find or insert an EXTERNNAME record for DDE links. */
494     virtual bool        InsertDde(
495                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
496                             const String& rApplic, const String& rTopic, const String& rItem ) = 0;
497 
498     virtual bool        InsertExtName(
499                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
500                             const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) = 0;
501 
502     /** Derived classes write the entire link table to the passed stream. */
503     virtual void        Save( XclExpStream& rStrm ) = 0;
504 
505 protected:
506     explicit            XclExpLinkManagerImpl( const XclExpRoot& rRoot );
507 };
508 
509 // ----------------------------------------------------------------------------
510 
511 /** Implementation of the link manager for BIFF5/BIFF7. */
512 class XclExpLinkManagerImpl5 : public XclExpLinkManagerImpl
513 {
514 public:
515     explicit            XclExpLinkManagerImpl5( const XclExpRoot& rRoot );
516 
517     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
518                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
519                             SCTAB nFirstScTab, SCTAB nLastScTab,
520                             XclExpRefLogEntry* pRefLogEntry );
521     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
522 
523     virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
524                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
525                                XclExpRefLogEntry* pRefLogEntry );
526 
527     virtual void        StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
528 
529     virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
530     virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
531 
532     virtual bool        InsertAddIn(
533                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
534                             const String& rName );
535 
536     /** InsertEuroTool */
537     virtual bool        InsertEuroTool(
538                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
539                              const String& rName );
540 
541     virtual bool        InsertDde(
542                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
543                             const String& rApplic, const String& rTopic, const String& rItem );
544 
545     virtual bool        InsertExtName(
546                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
547                             const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
548 
549     virtual void        Save( XclExpStream& rStrm );
550 
551 private:
552     typedef XclExpRecordList< XclExpExternSheet >   XclExpExtSheetList;
553     typedef XclExpExtSheetList::RecordRefType       XclExpExtSheetRef;
554     typedef ::std::map< SCTAB, sal_uInt16 >         XclExpIntTabMap;
555     typedef ::std::map< sal_Unicode, sal_uInt16 >   XclExpCodeMap;
556 
557 private:
558     /** Returns the number of EXTERNSHEET records. */
559     sal_uInt16          GetExtSheetCount() const;
560 
561     /** Appends an internal EXTERNSHEET record and returns the one-based index. */
562     sal_uInt16          AppendInternal( XclExpExtSheetRef xExtSheet );
563     /** Creates all EXTERNSHEET records for internal sheets on first call. */
564     void                CreateInternal();
565 
566     /** Returns the specified internal EXTERNSHEET record. */
567     XclExpExtSheetRef   GetInternal( sal_uInt16 nExtSheet );
568     /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
569     XclExpExtSheetRef   FindInternal( sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab );
570     /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
571     XclExpExtSheetRef   FindInternal( sal_uInt16& rnExtSheet, sal_Unicode cCode );
572 
573 private:
574     XclExpExtSheetList  maExtSheetList;     /// List with EXTERNSHEET records.
575     XclExpIntTabMap     maIntTabMap;        /// Maps internal Calc sheets to EXTERNSHEET records.
576     XclExpCodeMap       maCodeMap;          /// Maps special external codes to EXTERNSHEET records.
577 };
578 
579 // ----------------------------------------------------------------------------
580 
581 /** Implementation of the link manager for BIFF8. */
582 class XclExpLinkManagerImpl8 : public XclExpLinkManagerImpl
583 {
584 public:
585     explicit            XclExpLinkManagerImpl8( const XclExpRoot& rRoot );
586 
587     virtual void        FindExtSheet( sal_uInt16& rnExtSheet,
588                             sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
589                             SCTAB nFirstScTab, SCTAB nLastScTab,
590                             XclExpRefLogEntry* pRefLogEntry );
591     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
592 
593     virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
594                                sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
595                                XclExpRefLogEntry* pRefLogEntry );
596 
597     virtual void        StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
598 
599     virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
600     virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
601 
602     virtual bool        InsertAddIn(
603                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
604                             const String& rName );
605     /** InsertEuroTool */
606     virtual bool        InsertEuroTool(
607                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
608                             const String& rName );
609 
610     virtual bool        InsertDde(
611                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
612                             const String& rApplic, const String& rTopic, const String& rItem );
613 
614     virtual bool        InsertExtName(
615                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
616                             const String& rName, const ScExternalRefCache::TokenArrayRef pArray );
617 
618     virtual void        Save( XclExpStream& rStrm );
619 
620 private:
621     /** Searches for or inserts a new XTI structure.
622         @return  The 0-based list index of the XTI structure. */
623     sal_uInt16          InsertXti( const XclExpXti& rXti );
624 
625 private:
626     typedef ::std::vector< XclExpXti > XclExpXtiVec;
627 
628     XclExpSupbookBuffer maSBBuffer;     /// List of all SUPBOOK records.
629     XclExpXtiVec        maXtiVec;       /// List of XTI structures for the EXTERNSHEET record.
630 };
631 
632 // ============================================================================
633 // *** Implementation ***
634 // ============================================================================
635 
636 // Excel sheet indexes ========================================================
637 
638 const sal_uInt8 EXC_TABBUF_IGNORE   = 0x01;     /// Sheet will be ignored completely.
639 const sal_uInt8 EXC_TABBUF_EXTERN   = 0x02;     /// Sheet is linked externally.
640 const sal_uInt8 EXC_TABBUF_SKIPMASK = 0x0F;     /// Sheet will be skipped, if any flag is set.
641 const sal_uInt8 EXC_TABBUF_VISIBLE  = 0x10;     /// Sheet is visible.
642 const sal_uInt8 EXC_TABBUF_SELECTED = 0x20;     /// Sheet is selected.
643 const sal_uInt8 EXC_TABBUF_MIRRORED = 0x40;     /// Sheet is mirrored (right-to-left).
644 
645 // ----------------------------------------------------------------------------
646 
XclExpTabInfo(const XclExpRoot & rRoot)647 XclExpTabInfo::XclExpTabInfo( const XclExpRoot& rRoot ) :
648     XclExpRoot( rRoot ),
649     mnScCnt( 0 ),
650     mnXclCnt( 0 ),
651     mnXclExtCnt( 0 ),
652     mnXclSelCnt( 0 ),
653     mnDisplXclTab( 0 ),
654     mnFirstVisXclTab( 0 )
655 {
656     ScDocument& rDoc = GetDoc();
657     ScExtDocOptions& rDocOpt = GetExtDocOptions();
658 
659     mnScCnt = rDoc.GetTableCount();
660 
661     SCTAB nScTab;
662     SCTAB nFirstVisScTab = SCTAB_INVALID;   // first visible sheet
663     SCTAB nFirstExpScTab = SCTAB_INVALID;   // first exported sheet
664 
665     // --- initialize the flags in the index buffer ---
666 
667     maTabInfoVec.resize( mnScCnt );
668     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
669     {
670         // ignored sheets (skipped by export, with invalid Excel sheet index)
671         if( rDoc.IsScenario( nScTab ) )
672         {
673             SetFlag( nScTab, EXC_TABBUF_IGNORE );
674         }
675 
676         // external sheets (skipped, but with valid Excel sheet index for ref's)
677         else if( rDoc.GetLinkMode( nScTab ) == SC_LINK_VALUE )
678         {
679             SetFlag( nScTab, EXC_TABBUF_EXTERN );
680         }
681 
682         // exported sheets
683         else
684         {
685             // sheet name
686             rDoc.GetName( nScTab, maTabInfoVec[ nScTab ].maScName );
687 
688             // remember first exported sheet
689             if( nFirstExpScTab == SCTAB_INVALID )
690                nFirstExpScTab = nScTab;
691             // remember first visible exported sheet
692             if( (nFirstVisScTab == SCTAB_INVALID) && rDoc.IsVisible( nScTab ) )
693                nFirstVisScTab = nScTab;
694 
695             // sheet visible (only exported sheets)
696             SetFlag( nScTab, EXC_TABBUF_VISIBLE, rDoc.IsVisible( nScTab ) );
697 
698             // sheet selected (only exported sheets)
699             if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nScTab ) )
700                 SetFlag( nScTab, EXC_TABBUF_SELECTED, pTabSett->mbSelected );
701 
702             // sheet mirrored (only exported sheets)
703             SetFlag( nScTab, EXC_TABBUF_MIRRORED, rDoc.IsLayoutRTL( nScTab ) );
704         }
705     }
706 
707     // --- visible/selected sheets ---
708 
709     SCTAB nDisplScTab = rDocOpt.GetDocSettings().mnDisplTab;
710 
711     // #112908# find first visible exported sheet
712     if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
713     {
714         // no exportable visible sheet -> use first exportable sheet
715         nFirstVisScTab = nFirstExpScTab;
716         if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
717         {
718             // no exportable sheet at all -> use active sheet and export it
719             nFirstVisScTab = nDisplScTab;
720             SetFlag( nFirstVisScTab, EXC_TABBUF_SKIPMASK, false ); // clear skip flags
721         }
722         SetFlag( nFirstVisScTab, EXC_TABBUF_VISIBLE ); // must be visible, even if originally hidden
723     }
724 
725     // find currently displayed sheet
726     if( !IsExportTab( nDisplScTab ) )   // selected sheet not exported (i.e. scenario) -> use first visible
727         nDisplScTab = nFirstVisScTab;
728     SetFlag( nDisplScTab, EXC_TABBUF_VISIBLE | EXC_TABBUF_SELECTED );
729 
730     // number of selected sheets
731     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
732         if( IsSelectedTab( nScTab ) )
733             ++mnXclSelCnt;
734 
735     // --- calculate resulting Excel sheet indexes ---
736 
737     CalcXclIndexes();
738     mnFirstVisXclTab = GetXclTab( nFirstVisScTab );
739     mnDisplXclTab = GetXclTab( nDisplScTab );
740 
741     // --- sorted vectors for index lookup ---
742 
743     CalcSortedIndexes();
744 }
745 
IsExportTab(SCTAB nScTab) const746 bool XclExpTabInfo::IsExportTab( SCTAB nScTab ) const
747 {
748     /*  Check sheet index before to avoid assertion in GetFlag(). */
749     return (nScTab < mnScCnt) && !GetFlag( nScTab, EXC_TABBUF_SKIPMASK );
750 }
751 
IsExternalTab(SCTAB nScTab) const752 bool XclExpTabInfo::IsExternalTab( SCTAB nScTab ) const
753 {
754     /*  Check sheet index before to avoid assertion (called from formula
755         compiler also for deleted references). */
756     return (nScTab < mnScCnt) && GetFlag( nScTab, EXC_TABBUF_EXTERN );
757 }
758 
IsVisibleTab(SCTAB nScTab) const759 bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab ) const
760 {
761     return GetFlag( nScTab, EXC_TABBUF_VISIBLE );
762 }
763 
IsSelectedTab(SCTAB nScTab) const764 bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab ) const
765 {
766     return GetFlag( nScTab, EXC_TABBUF_SELECTED );
767 }
768 
IsDisplayedTab(SCTAB nScTab) const769 bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab ) const
770 {
771     DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
772     return GetXclTab( nScTab ) == mnDisplXclTab;
773 }
774 
IsMirroredTab(SCTAB nScTab) const775 bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab ) const
776 {
777     return GetFlag( nScTab, EXC_TABBUF_MIRRORED );
778 }
779 
GetScTabName(SCTAB nScTab) const780 const String& XclExpTabInfo::GetScTabName( SCTAB nScTab ) const
781 {
782     DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
783     return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].maScName : EMPTY_STRING;
784 }
785 
GetXclTab(SCTAB nScTab) const786 sal_uInt16 XclExpTabInfo::GetXclTab( SCTAB nScTab ) const
787 {
788     return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].mnXclTab : EXC_TAB_DELETED;
789 }
790 
GetRealScTab(SCTAB nSortedScTab) const791 SCTAB XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab ) const
792 {
793     DBG_ASSERT( nSortedScTab < mnScCnt, "XclExpTabInfo::GetRealScTab - sheet out of range" );
794     return (nSortedScTab < mnScCnt) ? maFromSortedVec[ nSortedScTab ] : SCTAB_INVALID;
795 }
796 
797 //UNUSED2009-05 SCTAB XclExpTabInfo::GetSortedScTab( SCTAB nScTab ) const
798 //UNUSED2009-05 {
799 //UNUSED2009-05     DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::GetSortedScTab - sheet out of range" );
800 //UNUSED2009-05     return (nScTab < mnScCnt) ? maToSortedVec[ nScTab ] : SCTAB_INVALID;
801 //UNUSED2009-05 }
802 
GetFlag(SCTAB nScTab,sal_uInt8 nFlags) const803 bool XclExpTabInfo::GetFlag( SCTAB nScTab, sal_uInt8 nFlags ) const
804 {
805     DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::GetFlag - sheet out of range" );
806     return (nScTab < mnScCnt) && ::get_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags );
807 }
808 
SetFlag(SCTAB nScTab,sal_uInt8 nFlags,bool bSet)809 void XclExpTabInfo::SetFlag( SCTAB nScTab, sal_uInt8 nFlags, bool bSet )
810 {
811     DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::SetFlag - sheet out of range" );
812     if( nScTab < mnScCnt )
813         ::set_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags, bSet );
814 }
815 
CalcXclIndexes()816 void XclExpTabInfo::CalcXclIndexes()
817 {
818     sal_uInt16 nXclTab = 0;
819     SCTAB nScTab = 0;
820 
821     // --- pass 1: process regular sheets ---
822     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
823     {
824         if( IsExportTab( nScTab ) )
825         {
826             maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
827             ++nXclTab;
828         }
829         else
830             maTabInfoVec[ nScTab ].mnXclTab = EXC_TAB_DELETED;
831     }
832     mnXclCnt = nXclTab;
833 
834     // --- pass 2: process external sheets (nXclTab continues) ---
835     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
836     {
837         if( IsExternalTab( nScTab ) )
838         {
839             maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
840             ++nXclTab;
841             ++mnXclExtCnt;
842         }
843     }
844 
845     // result: first occur all exported sheets, followed by all external sheets
846 }
847 
848 typedef ::std::pair< String, SCTAB >    XclExpTabName;
849 typedef ::std::vector< XclExpTabName >  XclExpTabNameVec;
850 
operator <(const XclExpTabName & rArg1,const XclExpTabName & rArg2)851 inline bool operator<( const XclExpTabName& rArg1, const XclExpTabName& rArg2 )
852 {
853     // compare the sheet names only
854     return ScGlobal::GetCollator()->compareString( rArg1.first, rArg2.first ) == COMPARE_LESS;
855 }
856 
CalcSortedIndexes()857 void XclExpTabInfo::CalcSortedIndexes()
858 {
859     ScDocument& rDoc = GetDoc();
860     XclExpTabNameVec aVec( mnScCnt );
861     SCTAB nScTab;
862 
863     // fill with sheet names
864     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
865     {
866         rDoc.GetName( nScTab, aVec[ nScTab ].first );
867         aVec[ nScTab ].second = nScTab;
868     }
869     ::std::sort( aVec.begin(), aVec.end() );
870 
871     // fill index vectors from sorted sheet name vector
872     maFromSortedVec.resize( mnScCnt );
873     maToSortedVec.resize( mnScCnt );
874     for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
875     {
876         maFromSortedVec[ nScTab ] = aVec[ nScTab ].second;
877         maToSortedVec[ aVec[ nScTab ].second ] = nScTab;
878     }
879 }
880 
881 // External names =============================================================
882 
XclExpExtNameBase(const XclExpRoot & rRoot,const String & rName,sal_uInt16 nFlags)883 XclExpExtNameBase::XclExpExtNameBase(
884         const XclExpRoot& rRoot, const String& rName, sal_uInt16 nFlags ) :
885     XclExpRecord( EXC_ID_EXTERNNAME ),
886     XclExpRoot( rRoot ),
887     maName( rName ),
888     mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ),
889     mnFlags( nFlags )
890 {
891     DBG_ASSERT( maName.Len() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
892     SetRecSize( 6 + mxName->GetSize() );
893 }
894 
~XclExpExtNameBase()895 XclExpExtNameBase::~XclExpExtNameBase()
896 {
897 }
898 
WriteBody(XclExpStream & rStrm)899 void XclExpExtNameBase::WriteBody( XclExpStream& rStrm )
900 {
901     rStrm   << mnFlags
902             << sal_uInt32( 0 )
903             << *mxName;
904     WriteAddData( rStrm );
905 }
906 
WriteAddData(XclExpStream &)907 void XclExpExtNameBase::WriteAddData( XclExpStream& /*rStrm*/ )
908 {
909 }
910 
911 // ----------------------------------------------------------------------------
912 
XclExpExtNameAddIn(const XclExpRoot & rRoot,const String & rName)913 XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName ) :
914     XclExpExtNameBase( rRoot, rName )
915 {
916     AddRecSize( 4 );
917 }
918 
WriteAddData(XclExpStream & rStrm)919 void XclExpExtNameAddIn::WriteAddData( XclExpStream& rStrm )
920 {
921     // write a #REF! error formula
922     rStrm << sal_uInt16( 2 ) << EXC_TOKID_ERR << EXC_ERR_REF;
923 }
924 
925 // ----------------------------------------------------------------------------
926 
XclExpExtNameDde(const XclExpRoot & rRoot,const String & rName,sal_uInt16 nFlags,const ScMatrix * pResults)927 XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot& rRoot,
928         const String& rName, sal_uInt16 nFlags, const ScMatrix* pResults ) :
929     XclExpExtNameBase( rRoot, rName, nFlags )
930 {
931     if( pResults )
932     {
933         mxMatrix.reset( new XclExpCachedMatrix( *pResults ) );
934         AddRecSize( mxMatrix->GetSize() );
935     }
936 }
937 
WriteAddData(XclExpStream & rStrm)938 void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
939 {
940     if( mxMatrix.is() )
941         mxMatrix->Save( rStrm );
942 }
943 
944 // ----------------------------------------------------------------------------
945 
XclExpExtName(const XclExpRoot & rRoot,const XclExpSupbook & rSupbook,const String & rName,const ScExternalRefCache::TokenArrayRef pArray)946 XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook,
947         const String& rName, const ScExternalRefCache::TokenArrayRef pArray ) :
948     XclExpExtNameBase( rRoot, rName ),
949     mrSupbook(rSupbook),
950     mpArray(pArray->Clone())
951 {
952 }
953 
WriteAddData(XclExpStream & rStrm)954 void XclExpExtName::WriteAddData( XclExpStream& rStrm )
955 {
956     // Write only if it only has a single token that is either a cell or cell
957     // range address.  Excel just writes '02 00 1C 17' for all the other types
958     // of external names.
959 
960     using namespace ::formula;
961     do
962     {
963         if (mpArray->GetLen() != 1)
964             break;
965 
966         const ScToken* p = static_cast<const ScToken*>(mpArray->First());
967         if (p->GetOpCode() != ocExternalRef)
968             break;
969 
970         switch (p->GetType())
971         {
972             case svExternalSingleRef:
973             {
974                 const ScSingleRefData& rRef = p->GetSingleRef();
975                 if (rRef.IsTabRel())
976                     break;
977 
978                 bool bColRel = rRef.IsColRel();
979                 bool bRowRel = rRef.IsRowRel();
980                 sal_uInt16 nCol = static_cast< sal_uInt16 >( bColRel ? rRef.nRelCol : rRef.nCol );
981                 sal_uInt16 nRow = static_cast< sal_uInt16 >( bRowRel ? rRef.nRelRow : rRef.nRow );
982                 if (bColRel) nCol |= 0x4000;
983                 if (bRowRel) nCol |= 0x8000;
984 
985                 const String& rTabName = p->GetString();
986                 sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
987 
988                 // size is always 9
989                 rStrm << static_cast<sal_uInt16>(9);
990                 // operator token (3A for cell reference)
991                 rStrm << static_cast<sal_uInt8>(0x3A);
992                 // cell address (Excel's address has 2 sheet IDs.)
993                 rStrm << nSBTab << nSBTab << nRow << nCol;
994                 return;
995             }
996             case svExternalDoubleRef:
997             {
998                 const ScComplexRefData& rRef = p->GetDoubleRef();
999                 const ScSingleRefData& r1 = rRef.Ref1;
1000                 const ScSingleRefData& r2 = rRef.Ref2;
1001                 if (r1.IsTabRel() || r2.IsTabRel())
1002                     break;
1003 
1004                 sal_uInt16 nTab1 = r1.nTab;
1005                 sal_uInt16 nTab2 = r2.nTab;
1006                 bool bCol1Rel = r1.IsColRel();
1007                 bool bRow1Rel = r1.IsRowRel();
1008                 bool bCol2Rel = r2.IsColRel();
1009                 bool bRow2Rel = r2.IsRowRel();
1010 
1011                 sal_uInt16 nCol1 = static_cast< sal_uInt16 >( bCol1Rel ? r1.nRelCol : r1.nCol );
1012                 sal_uInt16 nCol2 = static_cast< sal_uInt16 >( bCol2Rel ? r2.nRelCol : r2.nCol );
1013                 sal_uInt16 nRow1 = static_cast< sal_uInt16 >( bRow1Rel ? r1.nRelRow : r1.nRow );
1014                 sal_uInt16 nRow2 = static_cast< sal_uInt16 >( bRow2Rel ? r2.nRelRow : r2.nRow );
1015                 if (bCol1Rel) nCol1 |= 0x4000;
1016                 if (bRow1Rel) nCol1 |= 0x8000;
1017                 if (bCol2Rel) nCol2 |= 0x4000;
1018                 if (bRow2Rel) nCol2 |= 0x8000;
1019 
1020                 const String& rTabName = p->GetString();
1021                 sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
1022 
1023                 // size is always 13 (0x0D)
1024                 rStrm << static_cast<sal_uInt16>(13);
1025                 // operator token (3B for area reference)
1026                 rStrm << static_cast<sal_uInt8>(0x3B);
1027                 // range (area) address
1028                 sal_uInt16 nSBTab2 = nSBTab + nTab2 - nTab1;
1029                 rStrm << nSBTab << nSBTab2 << nRow1 << nRow2 << nCol1 << nCol2;
1030                 return;
1031             }
1032             default:
1033                 ;   // nothing
1034         }
1035     }
1036     while (false);
1037 
1038     // special value for #REF! (02 00 1C 17)
1039     rStrm << static_cast<sal_uInt16>(2) << EXC_TOKID_ERR << EXC_ERR_REF;
1040 }
1041 
1042 // List of external names =====================================================
1043 
XclExpExtNameBuffer(const XclExpRoot & rRoot)1044 XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
1045     XclExpRoot( rRoot )
1046 {
1047 }
1048 
InsertAddIn(const String & rName)1049 sal_uInt16 XclExpExtNameBuffer::InsertAddIn( const String& rName )
1050 {
1051     sal_uInt16 nIndex = GetIndex( rName );
1052     return nIndex ? nIndex : AppendNew( new XclExpExtNameAddIn( GetRoot(), rName ) );
1053 }
1054 
InsertEuroTool(const String & rName)1055 sal_uInt16 XclExpExtNameBuffer::InsertEuroTool( const String& rName )
1056 {
1057     sal_uInt16 nIndex = GetIndex( rName );
1058     return nIndex ? nIndex : AppendNew( new XclExpExtNameBase( GetRoot(), rName ) );
1059 }
1060 
InsertDde(const String & rApplic,const String & rTopic,const String & rItem)1061 sal_uInt16 XclExpExtNameBuffer::InsertDde(
1062         const String& rApplic, const String& rTopic, const String& rItem )
1063 {
1064     sal_uInt16 nIndex = GetIndex( rItem );
1065     if( nIndex == 0 )
1066     {
1067         sal_uInt16 nPos;
1068         if( GetDoc().FindDdeLink( rApplic, rTopic, rItem, SC_DDE_IGNOREMODE, nPos ) )
1069         {
1070             // create the leading 'StdDocumentName' EXTERNNAME record
1071             if( maNameList.IsEmpty() )
1072                 AppendNew( new XclExpExtNameDde(
1073                     GetRoot(), CREATE_STRING( "StdDocumentName" ), EXC_EXTN_EXPDDE_STDDOC ) );
1074 
1075             // try to find DDE result array, but create EXTERNNAME record without them too
1076             const ScMatrix* pScMatrix = GetDoc().GetDdeLinkResultMatrix( nPos );
1077             nIndex = AppendNew( new XclExpExtNameDde( GetRoot(), rItem, EXC_EXTN_EXPDDE, pScMatrix ) );
1078         }
1079     }
1080     return nIndex;
1081 }
1082 
InsertExtName(const XclExpSupbook & rSupbook,const String & rName,const ScExternalRefCache::TokenArrayRef pArray)1083 sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook,
1084         const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
1085 {
1086     sal_uInt16 nIndex = GetIndex( rName );
1087     return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, pArray ) );
1088 }
1089 
Save(XclExpStream & rStrm)1090 void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
1091 {
1092     maNameList.Save( rStrm );
1093 }
1094 
GetIndex(const String & rName) const1095 sal_uInt16 XclExpExtNameBuffer::GetIndex( const String& rName ) const
1096 {
1097     for( size_t nPos = 0, nSize = maNameList.GetSize(); nPos < nSize; ++nPos )
1098         if( maNameList.GetRecord( nPos )->GetName() == rName )
1099             return static_cast< sal_uInt16 >( nPos + 1 );
1100     return 0;
1101 }
1102 
AppendNew(XclExpExtNameBase * pExtName)1103 sal_uInt16 XclExpExtNameBuffer::AppendNew( XclExpExtNameBase* pExtName )
1104 {
1105     XclExpExtNameRef xExtName( pExtName );
1106     size_t nSize = maNameList.GetSize();
1107     if( nSize < 0x7FFF )
1108     {
1109         maNameList.AppendRecord( xExtName );
1110         return static_cast< sal_uInt16 >( nSize + 1 );
1111     }
1112     return 0;
1113 }
1114 
1115 // Cached external cells ======================================================
1116 
XclExpCrn(SCCOL nScCol,SCROW nScRow,const Any & rValue)1117 XclExpCrn::XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue ) :
1118     XclExpRecord( EXC_ID_CRN, 4 ),
1119     mnScCol( nScCol ),
1120     mnScRow( nScRow )
1121 {
1122     maValues.push_back( rValue );
1123 }
1124 
InsertValue(SCCOL nScCol,SCROW nScRow,const Any & rValue)1125 bool XclExpCrn::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
1126 {
1127     if( (nScRow != mnScRow) || (nScCol != static_cast< SCCOL >( mnScCol + maValues.size() )) )
1128         return false;
1129     maValues.push_back( rValue );
1130     return true;
1131 }
1132 
WriteBody(XclExpStream & rStrm)1133 void XclExpCrn::WriteBody( XclExpStream& rStrm )
1134 {
1135     rStrm   << static_cast< sal_uInt8 >( mnScCol + maValues.size() - 1 )
1136             << static_cast< sal_uInt8 >( mnScCol )
1137             << static_cast< sal_uInt16 >( mnScRow );
1138     for( CachedValues::iterator aIt = maValues.begin(), aEnd = maValues.end(); aIt != aEnd; ++aIt )
1139     {
1140         if( aIt->has< bool >() )
1141             WriteBool( rStrm, aIt->get< bool >() );
1142         else if( aIt->has< double >() )
1143             WriteDouble( rStrm, aIt->get< double >() );
1144         else if( aIt->has< OUString >() )
1145             WriteString( rStrm, aIt->get< OUString >() );
1146         else
1147             WriteEmpty( rStrm );
1148     }
1149 }
1150 
WriteBool(XclExpStream & rStrm,bool bValue)1151 void XclExpCrn::WriteBool( XclExpStream& rStrm, bool bValue )
1152 {
1153     rStrm << EXC_CACHEDVAL_BOOL << sal_uInt8( bValue ? 1 : 0);
1154     rStrm.WriteZeroBytes( 7 );
1155 }
1156 
WriteDouble(XclExpStream & rStrm,double fValue)1157 void XclExpCrn::WriteDouble( XclExpStream& rStrm, double fValue )
1158 {
1159     if( ::rtl::math::isNan( fValue ) )
1160     {
1161         sal_uInt16 nScError = static_cast< sal_uInt16 >( reinterpret_cast< const sal_math_Double* >( &fValue )->nan_parts.fraction_lo );
1162         WriteError( rStrm, XclTools::GetXclErrorCode( nScError ) );
1163     }
1164     else
1165     {
1166         rStrm << EXC_CACHEDVAL_DOUBLE << fValue;
1167     }
1168 }
1169 
WriteString(XclExpStream & rStrm,const OUString & rValue)1170 void XclExpCrn::WriteString( XclExpStream& rStrm, const OUString& rValue )
1171 {
1172     rStrm << EXC_CACHEDVAL_STRING << XclExpString( rValue );
1173 }
1174 
WriteError(XclExpStream & rStrm,sal_uInt8 nErrCode)1175 void XclExpCrn::WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode )
1176 {
1177     rStrm << EXC_CACHEDVAL_ERROR << nErrCode;
1178     rStrm.WriteZeroBytes( 7 );
1179 }
1180 
WriteEmpty(XclExpStream & rStrm)1181 void XclExpCrn::WriteEmpty( XclExpStream& rStrm )
1182 {
1183     rStrm << EXC_CACHEDVAL_EMPTY;
1184     rStrm.WriteZeroBytes( 8 );
1185 }
1186 
1187 // Cached cells of a sheet ====================================================
1188 
XclExpXct(const XclExpRoot & rRoot,const String & rTabName,sal_uInt16 nSBTab,ScExternalRefCache::TableTypeRef xCacheTable)1189 XclExpXct::XclExpXct( const XclExpRoot& rRoot, const String& rTabName,
1190         sal_uInt16 nSBTab, ScExternalRefCache::TableTypeRef xCacheTable ) :
1191     XclExpRoot( rRoot ),
1192     mxCacheTable( xCacheTable ),
1193     maBoundRange( ScAddress::INITIALIZE_INVALID ),
1194     maTabName( rTabName ),
1195     mnSBTab( nSBTab )
1196 {
1197 }
1198 
StoreCellRange(const ScRange & rRange)1199 void XclExpXct::StoreCellRange( const ScRange& rRange )
1200 {
1201     // #i70418# restrict size of external range to prevent memory overflow
1202     if( (rRange.aEnd.Col() - rRange.aStart.Col()) * (rRange.aEnd.Row() - rRange.aStart.Row()) > 1024 )
1203         return;
1204 
1205     maUsedCells.SetMultiMarkArea( rRange );
1206     maBoundRange.ExtendTo( rRange );
1207 }
1208 
StoreCell(const ScAddress & rCell,const::formula::FormulaToken & rToken)1209 void XclExpXct::StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken )
1210 {
1211     maUsedCells.SetMultiMarkArea( ScRange( rCell ) );
1212     maBoundRange.ExtendTo( ScRange( rCell ) );
1213     (void)rToken;
1214 }
1215 
StoreCellRange(const ScRange & rRange,const::formula::FormulaToken & rToken)1216 void XclExpXct::StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken )
1217 {
1218     maUsedCells.SetMultiMarkArea( rRange );
1219     maBoundRange.ExtendTo( rRange );
1220     (void)rToken;
1221 }
1222 
1223 namespace {
1224 
1225 class XclExpCrnList : public XclExpRecordList< XclExpCrn >
1226 {
1227 public:
1228     /** Inserts the passed value into an existing or new CRN record.
1229         @return  True = value inserted successfully, false = CRN list is full. */
1230     bool                InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
1231 };
1232 
InsertValue(SCCOL nScCol,SCROW nScRow,const Any & rValue)1233 bool XclExpCrnList::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
1234 {
1235     RecordRefType xLastRec = GetLastRecord();
1236     if( xLastRec.is() && xLastRec->InsertValue( nScCol, nScRow, rValue ) )
1237         return true;
1238     if( GetSize() == SAL_MAX_UINT16 )
1239         return false;
1240     AppendNewRecord( new XclExpCrn( nScCol, nScRow, rValue ) );
1241     return true;
1242 }
1243 
1244 } // namespace
1245 
Save(XclExpStream & rStrm)1246 void XclExpXct::Save( XclExpStream& rStrm )
1247 {
1248     if( !mxCacheTable )
1249         return;
1250 
1251     /*  Get the range of used rows in the cache table. This may help to
1252         optimize building the CRN record list if the cache table does not
1253         contain all referred cells, e.g. if big empty ranges are used in the
1254         formulas. */
1255     ::std::pair< SCROW, SCROW > aRowRange = mxCacheTable->getRowRange();
1256     if( aRowRange.first >= aRowRange.second )
1257         return;
1258 
1259     /*  Crop the bounding range of used cells in this table to Excel limits.
1260         Return if there is no external cell inside these limits. */
1261     if( !GetAddressConverter().ValidateRange( maBoundRange, false ) )
1262         return;
1263 
1264     /*  Find the resulting row range that needs to be processed. */
1265     SCROW nScRow1 = ::std::max( aRowRange.first, maBoundRange.aStart.Row() );
1266     SCROW nScRow2 = ::std::min( aRowRange.second - 1, maBoundRange.aEnd.Row() );
1267     if( nScRow1 > nScRow2 )
1268         return;
1269 
1270     /*  Build and collect all CRN records before writing the XCT record. This
1271         is needed to determine the total number of CRN records which must be
1272         known when writing the XCT record (possibly encrypted, so seeking the
1273         output strem back after writing the CRN records is not an option). */
1274     XclExpCrnList aCrnRecs;
1275     SvNumberFormatter& rFormatter = GetFormatter();
1276     bool bValid = true;
1277     for( SCROW nScRow = nScRow1; bValid && (nScRow <= nScRow2); ++nScRow )
1278     {
1279         ::std::pair< SCCOL, SCCOL > aColRange = mxCacheTable->getColRange( nScRow );
1280         for( SCCOL nScCol = aColRange.first; bValid && (nScCol < aColRange.second); ++nScCol )
1281         {
1282             if( maUsedCells.IsCellMarked( nScCol, nScRow, sal_True ) )
1283             {
1284                 sal_uInt32 nScNumFmt = 0;
1285                 ScExternalRefCache::TokenRef xToken = mxCacheTable->getCell( nScCol, nScRow, &nScNumFmt );
1286                 using namespace ::formula;
1287                 if( xToken.get() ) switch( xToken->GetType() )
1288                 {
1289                     case svDouble:
1290                         bValid = (rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL) ?
1291                             aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() != 0 ) ) :
1292                             aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() ) );
1293                     break;
1294                     case svString:
1295                         // do not save empty strings (empty cells) to cache
1296                         if( xToken->GetString().Len() > 0 )
1297                             bValid = aCrnRecs.InsertValue( nScCol, nScRow, Any( OUString( xToken->GetString() ) ) );
1298                     break;
1299                     default:
1300                     break;
1301                 }
1302             }
1303         }
1304     }
1305 
1306     // write the XCT record and the list of CRN records
1307     rStrm.StartRecord( EXC_ID_XCT, 4 );
1308     rStrm << static_cast< sal_uInt16 >( aCrnRecs.GetSize() ) << mnSBTab;
1309     rStrm.EndRecord();
1310     aCrnRecs.Save( rStrm );
1311 }
1312 
1313 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
1314 
XclExpExternSheetBase(const XclExpRoot & rRoot,sal_uInt16 nRecId,sal_uInt32 nRecSize)1315 XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot& rRoot, sal_uInt16 nRecId, sal_uInt32 nRecSize ) :
1316     XclExpRecord( nRecId, nRecSize ),
1317     XclExpRoot( rRoot )
1318 {
1319 }
1320 
GetExtNameBuffer()1321 XclExpExtNameBuffer& XclExpExternSheetBase::GetExtNameBuffer()
1322 {
1323     if( !mxExtNameBfr )
1324         mxExtNameBfr.reset( new XclExpExtNameBuffer( GetRoot() ) );
1325     return *mxExtNameBfr;
1326 }
1327 
WriteExtNameBuffer(XclExpStream & rStrm)1328 void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream& rStrm )
1329 {
1330     if( mxExtNameBfr.is() )
1331         mxExtNameBfr->Save( rStrm );
1332 }
1333 
1334 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
1335 
XclExpExternSheet(const XclExpRoot & rRoot,sal_Unicode cCode)1336 XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode ) :
1337     XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
1338 {
1339     Init( String( cCode ) );
1340 }
1341 
XclExpExternSheet(const XclExpRoot & rRoot,const String & rTabName)1342 XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName ) :
1343     XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
1344 {
1345     // reference to own sheet: \03<sheetname>
1346     Init( String( EXC_EXTSH_TABNAME ).Append( rTabName ) );
1347 }
1348 
Save(XclExpStream & rStrm)1349 void XclExpExternSheet::Save( XclExpStream& rStrm )
1350 {
1351     // EXTERNSHEET record
1352     XclExpRecord::Save( rStrm );
1353     // EXTERNNAME records
1354     WriteExtNameBuffer( rStrm );
1355 }
1356 
Init(const String & rEncUrl)1357 void XclExpExternSheet::Init( const String& rEncUrl )
1358 {
1359     DBG_ASSERT_BIFF( GetBiff() <= EXC_BIFF5 );
1360     maTabName.AssignByte( rEncUrl, GetTextEncoding(), EXC_STR_8BITLENGTH );
1361     SetRecSize( maTabName.GetSize() );
1362 }
1363 
InsertAddIn(const String & rName)1364 sal_uInt16 XclExpExternSheet::InsertAddIn( const String& rName )
1365 {
1366     return GetExtNameBuffer().InsertAddIn( rName );
1367 }
1368 
WriteBody(XclExpStream & rStrm)1369 void XclExpExternSheet::WriteBody( XclExpStream& rStrm )
1370 {
1371     sal_uInt8 nNameSize = static_cast< sal_uInt8 >( maTabName.Len() );
1372     // special case: reference to own sheet (starting with '\03') needs wrong string length
1373     if( maTabName.GetChar( 0 ) == EXC_EXTSH_TABNAME )
1374         --nNameSize;
1375     rStrm << nNameSize;
1376     maTabName.WriteBuffer( rStrm );
1377 }
1378 
1379 // External document (SUPBOOK, BIFF8) =========================================
1380 
XclExpSupbook(const XclExpRoot & rRoot,sal_uInt16 nXclTabCount)1381 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount ) :
1382     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1383     meType( EXC_SBTYPE_SELF ),
1384     mnXclTabCount( nXclTabCount )
1385 {
1386 }
1387 
XclExpSupbook(const XclExpRoot & rRoot)1388 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot ) :
1389     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1390     meType( EXC_SBTYPE_ADDIN ),
1391     mnXclTabCount( 1 )
1392 {
1393 }
1394 
XclExpSupbook(const XclExpRoot & rRoot,const String & rUrl,XclSupbookType)1395 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType ) :
1396     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
1397     maUrl( rUrl ),
1398     maUrlEncoded( rUrl ),
1399     meType( EXC_SBTYPE_EUROTOOL ),
1400     mnXclTabCount( 0 )
1401 {
1402     SetRecSize( 2 + maUrlEncoded.GetSize() );
1403 }
1404 
1405 
XclExpSupbook(const XclExpRoot & rRoot,const String & rUrl)1406 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) :
1407     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
1408     maUrl( rUrl ),
1409     maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot, rUrl ) ),
1410     meType( EXC_SBTYPE_EXTERN ),
1411     mnXclTabCount( 0 )
1412 {
1413     SetRecSize( 2 + maUrlEncoded.GetSize() );
1414 
1415     // We need to create all tables up front to ensure the correct table order.
1416     ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager();
1417     sal_uInt16 nFileId = pRefMgr->getExternalFileId( rUrl );
1418     ScfStringVec aTabNames;
1419     pRefMgr->getAllCachedTableNames( nFileId, aTabNames );
1420     for( ScfStringVec::const_iterator aBeg = aTabNames.begin(), aIt = aBeg, aEnd = aTabNames.end(); aIt != aEnd; ++aIt )
1421         InsertTabName( *aIt, pRefMgr->getCacheTable( nFileId, aIt - aBeg ) );
1422 }
1423 
XclExpSupbook(const XclExpRoot & rRoot,const String & rApplic,const String & rTopic)1424 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) :
1425     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
1426     maUrl( rApplic ),
1427     maDdeTopic( rTopic ),
1428     maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic, rTopic ) ),
1429     meType( EXC_SBTYPE_SPECIAL ),
1430     mnXclTabCount( 0 )
1431 {
1432     SetRecSize( 2 + maUrlEncoded.GetSize() );
1433 }
1434 
IsUrlLink(const String & rUrl) const1435 bool XclExpSupbook::IsUrlLink( const String& rUrl ) const
1436 {
1437     return (meType == EXC_SBTYPE_EXTERN || meType == EXC_SBTYPE_EUROTOOL) && (maUrl == rUrl);
1438 }
1439 
IsDdeLink(const String & rApplic,const String & rTopic) const1440 bool XclExpSupbook::IsDdeLink( const String& rApplic, const String& rTopic ) const
1441 {
1442     return (meType == EXC_SBTYPE_SPECIAL) && (maUrl == rApplic) && (maDdeTopic == rTopic);
1443 }
1444 
FillRefLogEntry(XclExpRefLogEntry & rRefLogEntry,sal_uInt16 nFirstSBTab,sal_uInt16 nLastSBTab) const1445 void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
1446         sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const
1447 {
1448     rRefLogEntry.mpUrl = maUrlEncoded.IsEmpty() ? 0 : &maUrlEncoded;
1449     rRefLogEntry.mpFirstTab = GetTabName( nFirstSBTab );
1450     rRefLogEntry.mpLastTab = GetTabName( nLastSBTab );
1451 }
1452 
StoreCellRange(const ScRange & rRange,sal_uInt16 nSBTab)1453 void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
1454 {
1455     if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1456         pXct->StoreCellRange( rRange );
1457 }
1458 
StoreCell(sal_uInt16 nSBTab,const ScAddress & rCell,const formula::FormulaToken & rToken)1459 void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const formula::FormulaToken& rToken )
1460 {
1461     if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1462         pXct->StoreCell( rCell, rToken );
1463 }
1464 
StoreCellRange(sal_uInt16 nSBTab,const ScRange & rRange,const formula::FormulaToken & rToken)1465 void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const formula::FormulaToken& rToken )
1466 {
1467     // multi-table range is not allowed!
1468     if( rRange.aStart.Tab() == rRange.aEnd.Tab() )
1469         if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
1470             pXct->StoreCellRange( rRange, rToken );
1471 }
1472 
GetTabIndex(const String & rTabName) const1473 sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName ) const
1474 {
1475     XclExpString aXclName(rTabName);
1476     size_t nSize = maXctList.GetSize();
1477     for (size_t i = 0; i < nSize; ++i)
1478     {
1479         XclExpXctRef aRec = maXctList.GetRecord(i);
1480         if (aXclName == aRec->GetTabName())
1481             return ulimit_cast<sal_uInt16>(i);
1482     }
1483     return EXC_NOTAB;
1484 }
1485 
GetTabCount() const1486 sal_uInt16 XclExpSupbook::GetTabCount() const
1487 {
1488     return ulimit_cast<sal_uInt16>(maXctList.GetSize());
1489 }
1490 
InsertTabName(const String & rTabName,ScExternalRefCache::TableTypeRef xCacheTable)1491 sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName, ScExternalRefCache::TableTypeRef xCacheTable )
1492 {
1493     DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
1494     sal_uInt16 nSBTab = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
1495     XclExpXctRef xXct( new XclExpXct( GetRoot(), rTabName, nSBTab, xCacheTable ) );
1496     AddRecSize( xXct->GetTabName().GetSize() );
1497     maXctList.AppendRecord( xXct );
1498     return nSBTab;
1499 }
1500 
InsertAddIn(const String & rName)1501 sal_uInt16 XclExpSupbook::InsertAddIn( const String& rName )
1502 {
1503     return GetExtNameBuffer().InsertAddIn( rName );
1504 }
1505 
InsertEuroTool(const String & rName)1506 sal_uInt16 XclExpSupbook::InsertEuroTool( const String& rName )
1507 {
1508     return GetExtNameBuffer().InsertEuroTool( rName );
1509 }
1510 
InsertDde(const String & rItem)1511 sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
1512 {
1513     return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
1514 }
1515 
InsertExtName(const String & rName,const ScExternalRefCache::TokenArrayRef pArray)1516 sal_uInt16 XclExpSupbook::InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
1517 {
1518     return GetExtNameBuffer().InsertExtName(*this, rName, pArray);
1519 }
1520 
Save(XclExpStream & rStrm)1521 void XclExpSupbook::Save( XclExpStream& rStrm )
1522 {
1523     // SUPBOOK record
1524     XclExpRecord::Save( rStrm );
1525     // XCT record, CRN records
1526     maXctList.Save( rStrm );
1527     // EXTERNNAME records
1528     WriteExtNameBuffer( rStrm );
1529 }
1530 
GetTabName(sal_uInt16 nSBTab) const1531 const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
1532 {
1533     XclExpXctRef xXct = maXctList.GetRecord( nSBTab );
1534     return xXct.is() ? &xXct->GetTabName() : 0;
1535 }
1536 
WriteBody(XclExpStream & rStrm)1537 void XclExpSupbook::WriteBody( XclExpStream& rStrm )
1538 {
1539     switch( meType )
1540     {
1541         case EXC_SBTYPE_SELF:
1542             rStrm << mnXclTabCount << EXC_SUPB_SELF;
1543         break;
1544         case EXC_SBTYPE_EXTERN:
1545         case EXC_SBTYPE_SPECIAL:
1546         case EXC_SBTYPE_EUROTOOL:
1547         {
1548             sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
1549             rStrm << nCount << maUrlEncoded;
1550 
1551             for( size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos )
1552                 rStrm << maXctList.GetRecord( nPos )->GetTabName();
1553         }
1554         break;
1555         case EXC_SBTYPE_ADDIN:
1556             rStrm << mnXclTabCount << EXC_SUPB_ADDIN;
1557         break;
1558         default:
1559             DBG_ERRORFILE( "XclExpSupbook::WriteBody - unknown SUPBOOK type" );
1560     }
1561 }
1562 
1563 // All SUPBOOKS in a document =================================================
1564 
XclExpSupbookBuffer(const XclExpRoot & rRoot)1565 XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
1566     XclExpRoot( rRoot ),
1567     mnOwnDocSB( SAL_MAX_UINT16 ),
1568     mnAddInSB( SAL_MAX_UINT16 )
1569 {
1570     XclExpTabInfo& rTabInfo = GetTabInfo();
1571     sal_uInt16 nXclCnt = rTabInfo.GetXclTabCount();
1572     sal_uInt16 nCodeCnt = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
1573     size_t nCount = nXclCnt + rTabInfo.GetXclExtTabCount();
1574 
1575     DBG_ASSERT( nCount > 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
1576     if( nCount )
1577     {
1578         maSBIndexVec.resize( nCount );
1579 
1580         // self-ref SUPBOOK first of list
1581         XclExpSupbookRef xSupbook( new XclExpSupbook( GetRoot(), ::std::max( nXclCnt, nCodeCnt ) ) );
1582         mnOwnDocSB = Append( xSupbook );
1583         for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
1584             maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
1585     }
1586 }
1587 
GetXti(sal_uInt16 nFirstXclTab,sal_uInt16 nLastXclTab,XclExpRefLogEntry * pRefLogEntry) const1588 XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
1589         XclExpRefLogEntry* pRefLogEntry ) const
1590 {
1591     XclExpXti aXti;
1592     size_t nSize = maSBIndexVec.size();
1593     if( (nFirstXclTab < nSize) && (nLastXclTab < nSize) )
1594     {
1595         // index of the SUPBOOK record
1596         aXti.mnSupbook = maSBIndexVec[ nFirstXclTab ].mnSupbook;
1597 
1598         // all sheets in the same supbook?
1599         bool bSameSB = true;
1600         for( sal_uInt16 nXclTab = nFirstXclTab + 1; bSameSB && (nXclTab <= nLastXclTab); ++nXclTab )
1601         {
1602             bSameSB = maSBIndexVec[ nXclTab ].mnSupbook == aXti.mnSupbook;
1603             if( !bSameSB )
1604                 nLastXclTab = nXclTab - 1;
1605         }
1606         aXti.mnFirstSBTab = maSBIndexVec[ nFirstXclTab ].mnSBTab;
1607         aXti.mnLastSBTab = maSBIndexVec[ nLastXclTab ].mnSBTab;
1608 
1609         // fill external reference log entry (for change tracking)
1610         if( pRefLogEntry )
1611         {
1612             pRefLogEntry->mnFirstXclTab = nFirstXclTab;
1613             pRefLogEntry->mnLastXclTab = nLastXclTab;
1614             XclExpSupbookRef xSupbook = maSupbookList.GetRecord( aXti.mnSupbook );
1615             if( xSupbook.is() )
1616                 xSupbook->FillRefLogEntry( *pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab );
1617         }
1618     }
1619     else
1620     {
1621         // special range, i.e. for deleted sheets or add-ins
1622         aXti.mnSupbook = mnOwnDocSB;
1623         aXti.mnFirstSBTab = nFirstXclTab;
1624         aXti.mnLastSBTab = nLastXclTab;
1625     }
1626 
1627     return aXti;
1628 }
1629 
StoreCellRange(const ScRange & rRange)1630 void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
1631 {
1632     sal_uInt16 nXclTab = GetTabInfo().GetXclTab( rRange.aStart.Tab() );
1633     if( nXclTab < maSBIndexVec.size() )
1634     {
1635         const XclExpSBIndex& rSBIndex = maSBIndexVec[ nXclTab ];
1636         XclExpSupbookRef xSupbook = maSupbookList.GetRecord( rSBIndex.mnSupbook );
1637         DBG_ASSERT( xSupbook.is(), "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
1638         if( xSupbook.is() )
1639             xSupbook->StoreCellRange( rRange, rSBIndex.mnSBTab );
1640     }
1641 }
1642 
1643 namespace {
1644 
1645 class FindSBIndexEntry
1646 {
1647 public:
FindSBIndexEntry(sal_uInt16 nSupbookId,sal_uInt16 nTabId)1648     explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) :
1649         mnSupbookId(nSupbookId), mnTabId(nTabId) {}
1650 
operator ()(const XclExpSupbookBuffer::XclExpSBIndex & r) const1651     bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const
1652     {
1653         return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab;
1654     }
1655 
1656 private:
1657     sal_uInt16 mnSupbookId;
1658     sal_uInt16 mnTabId;
1659 };
1660 
1661 }
1662 
StoreCell(sal_uInt16 nFileId,const String & rTabName,const ScAddress & rCell)1663 void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell )
1664 {
1665     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
1666     const String* pUrl = pRefMgr->getExternalFileName(nFileId);
1667     if (!pUrl)
1668         return;
1669 
1670     XclExpSupbookRef xSupbook;
1671     sal_uInt16 nSupbookId;
1672     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
1673     {
1674         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
1675         nSupbookId = Append(xSupbook);
1676     }
1677 
1678     ScExternalRefCache::TokenRef pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL);
1679     if (!pToken.get())
1680         return;
1681 
1682     sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
1683     if (nSheetId == EXC_NOTAB)
1684         // specified table name not found in this SUPBOOK.
1685         return;
1686 
1687     FindSBIndexEntry f(nSupbookId, nSheetId);
1688     XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
1689     XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
1690     if (itr == itrEnd)
1691     {
1692         maSBIndexVec.push_back(XclExpSBIndex());
1693         XclExpSBIndex& r = maSBIndexVec.back();
1694         r.mnSupbook = nSupbookId;
1695         r.mnSBTab   = nSheetId;
1696     }
1697 
1698     xSupbook->StoreCell(nSheetId, rCell, *pToken);
1699 }
1700 
StoreCellRange(sal_uInt16 nFileId,const String & rTabName,const ScRange & rRange)1701 void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange )
1702 {
1703     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
1704     const String* pUrl = pRefMgr->getExternalFileName(nFileId);
1705     if (!pUrl)
1706         return;
1707 
1708     XclExpSupbookRef xSupbook;
1709     sal_uInt16 nSupbookId;
1710     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
1711     {
1712         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
1713         nSupbookId = Append(xSupbook);
1714     }
1715 
1716     SCTAB nTabCount = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
1717 
1718     // If this is a multi-table range, get token for each table.
1719     using namespace ::formula;
1720     vector<FormulaToken*> aMatrixList;
1721     aMatrixList.reserve(nTabCount);
1722 
1723     // This is a new'ed instance, so we must manage its life cycle here.
1724     ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
1725     if (!pArray.get())
1726         return;
1727 
1728     for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
1729     {
1730         if (p->GetType() == svMatrix)
1731             aMatrixList.push_back(p);
1732         else if (p->GetOpCode() != ocSep)
1733         {
1734             // This is supposed to be ocSep!!!
1735             return;
1736         }
1737     }
1738 
1739     if (aMatrixList.size() != static_cast<size_t>(nTabCount))
1740     {
1741         // matrix size mis-match !
1742         return;
1743     }
1744 
1745     sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
1746 
1747     ScRange aRange(rRange);
1748     aRange.aStart.SetTab(0);
1749     aRange.aEnd.SetTab(0);
1750     for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
1751     {
1752         sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab);
1753         FindSBIndexEntry f(nSupbookId, nSheetId);
1754         XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
1755         XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
1756         if (itr == itrEnd)
1757         {
1758             maSBIndexVec.push_back(XclExpSBIndex());
1759             XclExpSBIndex& r = maSBIndexVec.back();
1760             r.mnSupbook = nSupbookId;
1761             r.mnSBTab   = nSheetId;
1762         }
1763 
1764         xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab]);
1765     }
1766 }
1767 
InsertAddIn(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const String & rName)1768 bool XclExpSupbookBuffer::InsertAddIn(
1769         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
1770 {
1771     XclExpSupbookRef xSupbook;
1772     if( mnAddInSB == SAL_MAX_UINT16 )
1773     {
1774         xSupbook.reset( new XclExpSupbook( GetRoot() ) );
1775         mnAddInSB = Append( xSupbook );
1776     }
1777     else
1778         xSupbook = maSupbookList.GetRecord( mnAddInSB );
1779     DBG_ASSERT( xSupbook.is(), "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
1780     rnSupbook = mnAddInSB;
1781     rnExtName = xSupbook->InsertAddIn( rName );
1782     return rnExtName > 0;
1783 }
1784 
InsertEuroTool(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const String & rName)1785 bool XclExpSupbookBuffer::InsertEuroTool(
1786         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
1787 {
1788     XclExpSupbookRef xSupbook;
1789     String aUrl( RTL_CONSTASCII_USTRINGPARAM("\001\010EUROTOOL.XLA"));
1790     if( !GetSupbookUrl( xSupbook, rnSupbook, aUrl ) )
1791     {
1792         xSupbook.reset( new XclExpSupbook( GetRoot(), aUrl, EXC_SBTYPE_EUROTOOL ) );
1793         rnSupbook = Append( xSupbook );
1794     }
1795     rnExtName = xSupbook->InsertEuroTool( rName );
1796     return rnExtName > 0;
1797 }
1798 
InsertDde(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const String & rApplic,const String & rTopic,const String & rItem)1799 bool XclExpSupbookBuffer::InsertDde(
1800         sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
1801         const String& rApplic, const String& rTopic, const String& rItem )
1802 {
1803     XclExpSupbookRef xSupbook;
1804     if( !GetSupbookDde( xSupbook, rnSupbook, rApplic, rTopic ) )
1805     {
1806         xSupbook.reset( new XclExpSupbook( GetRoot(), rApplic, rTopic ) );
1807         rnSupbook = Append( xSupbook );
1808     }
1809     rnExtName = xSupbook->InsertDde( rItem );
1810     return rnExtName > 0;
1811 }
1812 
InsertExtName(sal_uInt16 & rnSupbook,sal_uInt16 & rnExtName,const String & rUrl,const String & rName,const ScExternalRefCache::TokenArrayRef pArray)1813 bool XclExpSupbookBuffer::InsertExtName(
1814         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
1815         const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
1816 {
1817     XclExpSupbookRef xSupbook;
1818     if (!GetSupbookUrl(xSupbook, rnSupbook, rUrl))
1819     {
1820         xSupbook.reset( new XclExpSupbook(GetRoot(), rUrl) );
1821         rnSupbook = Append(xSupbook);
1822     }
1823     rnExtName = xSupbook->InsertExtName(rName, pArray);
1824     return rnExtName > 0;
1825 }
1826 
GetXti(sal_uInt16 nFileId,const String & rTabName,sal_uInt16 nXclTabSpan,XclExpRefLogEntry * pRefLogEntry)1827 XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
1828                                        XclExpRefLogEntry* pRefLogEntry )
1829 {
1830     XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB);
1831     ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
1832     const String* pUrl = pRefMgr->getExternalFileName(nFileId);
1833     if (!pUrl)
1834         return aXti;
1835 
1836     XclExpSupbookRef xSupbook;
1837     sal_uInt16 nSupbookId;
1838     if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
1839     {
1840         xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
1841         nSupbookId = Append(xSupbook);
1842     }
1843     aXti.mnSupbook = nSupbookId;
1844 
1845     sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
1846     if (nFirstSheetId == EXC_NOTAB)
1847     {
1848         // first sheet not found in SUPBOOK.
1849         return aXti;
1850     }
1851     sal_uInt16 nSheetCount = xSupbook->GetTabCount();
1852     for (sal_uInt16 i = 0; i < nXclTabSpan; ++i)
1853     {
1854         sal_uInt16 nSheetId = nFirstSheetId + i;
1855         if (nSheetId >= nSheetCount)
1856             return aXti;
1857 
1858         FindSBIndexEntry f(nSupbookId, nSheetId);
1859         XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
1860         XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
1861         if (itr == itrEnd)
1862         {
1863             maSBIndexVec.push_back(XclExpSBIndex());
1864             XclExpSBIndex& r = maSBIndexVec.back();
1865             r.mnSupbook = nSupbookId;
1866             r.mnSBTab   = nSheetId;
1867         }
1868         if (i == 0)
1869             aXti.mnFirstSBTab = nSheetId;
1870         if (i == nXclTabSpan - 1)
1871             aXti.mnLastSBTab = nSheetId;
1872     }
1873 
1874     if (pRefLogEntry)
1875     {
1876         pRefLogEntry->mnFirstXclTab = 0;
1877         pRefLogEntry->mnLastXclTab  = 0;
1878         if (xSupbook.is())
1879             xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
1880     }
1881 
1882     return aXti;
1883 }
1884 
Save(XclExpStream & rStrm)1885 void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
1886 {
1887     maSupbookList.Save( rStrm );
1888 }
1889 
GetSupbookUrl(XclExpSupbookRef & rxSupbook,sal_uInt16 & rnIndex,const String & rUrl) const1890 bool XclExpSupbookBuffer::GetSupbookUrl(
1891         XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex, const String& rUrl ) const
1892 {
1893     for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
1894     {
1895         rxSupbook = maSupbookList.GetRecord( nPos );
1896         if( rxSupbook->IsUrlLink( rUrl ) )
1897         {
1898             rnIndex = ulimit_cast< sal_uInt16 >( nPos );
1899             return true;
1900         }
1901     }
1902     return false;
1903 }
1904 
GetSupbookDde(XclExpSupbookRef & rxSupbook,sal_uInt16 & rnIndex,const String & rApplic,const String & rTopic) const1905 bool XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef& rxSupbook,
1906         sal_uInt16& rnIndex, const String& rApplic, const String& rTopic ) const
1907 {
1908     for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
1909     {
1910         rxSupbook = maSupbookList.GetRecord( nPos );
1911         if( rxSupbook->IsDdeLink( rApplic, rTopic ) )
1912         {
1913             rnIndex = ulimit_cast< sal_uInt16 >( nPos );
1914             return true;
1915         }
1916     }
1917     return false;
1918 }
1919 
Append(XclExpSupbookRef xSupbook)1920 sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
1921 {
1922     maSupbookList.AppendRecord( xSupbook );
1923     return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
1924 }
1925 
1926 // Export link manager ========================================================
1927 
XclExpLinkManagerImpl(const XclExpRoot & rRoot)1928 XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
1929     XclExpRoot( rRoot )
1930 {
1931 }
1932 
1933 // ----------------------------------------------------------------------------
1934 
XclExpLinkManagerImpl5(const XclExpRoot & rRoot)1935 XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot& rRoot ) :
1936     XclExpLinkManagerImpl( rRoot )
1937 {
1938 }
1939 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)1940 void XclExpLinkManagerImpl5::FindExtSheet(
1941         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
1942         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
1943 {
1944     FindInternal( rnExtSheet, rnFirstXclTab, nFirstScTab );
1945     if( (rnFirstXclTab == EXC_TAB_DELETED) || (nFirstScTab == nLastScTab) )
1946     {
1947         rnLastXclTab = rnFirstXclTab;
1948     }
1949     else
1950     {
1951         sal_uInt16 nDummyExtSheet;
1952         FindInternal( nDummyExtSheet, rnLastXclTab, nLastScTab );
1953     }
1954 
1955     (void)pRefLogEntry;     // avoid compiler warning
1956     DBG_ASSERT( !pRefLogEntry, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
1957 }
1958 
FindExtSheet(sal_Unicode cCode)1959 sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
1960 {
1961     sal_uInt16 nExtSheet;
1962     FindInternal( nExtSheet, cCode );
1963     return nExtSheet;
1964 }
1965 
FindExtSheet(sal_uInt16,const String &,sal_uInt16,sal_uInt16 &,sal_uInt16 &,sal_uInt16 &,XclExpRefLogEntry *)1966 void XclExpLinkManagerImpl5::FindExtSheet(
1967     sal_uInt16 /*nFileId*/, const String& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/,
1968     sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/,
1969     XclExpRefLogEntry* /*pRefLogEntry*/ )
1970 {
1971     // not implemented
1972 }
1973 
StoreCellRange(const ScSingleRefData &,const ScSingleRefData &)1974 void XclExpLinkManagerImpl5::StoreCellRange( const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
1975 {
1976     // not implemented
1977 }
1978 
StoreCell(sal_uInt16,const String &,const ScSingleRefData &)1979 void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef*/ )
1980 {
1981     // not implemented
1982 }
1983 
StoreCellRange(sal_uInt16,const String &,const ScSingleRefData &,const ScSingleRefData &)1984 void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
1985 {
1986     // not implemented
1987 }
1988 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName)1989 bool XclExpLinkManagerImpl5::InsertAddIn(
1990         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
1991 {
1992     XclExpExtSheetRef xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_ADDIN );
1993     if( xExtSheet.is() )
1994     {
1995         rnExtName = xExtSheet->InsertAddIn( rName );
1996         return rnExtName > 0;
1997     }
1998     return false;
1999 }
2000 
InsertEuroTool(sal_uInt16 &,sal_uInt16 &,const String &)2001 bool XclExpLinkManagerImpl5::InsertEuroTool(
2002          sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rName*/ )
2003 {
2004      return false;
2005 }
2006 
2007 
InsertDde(sal_uInt16 &,sal_uInt16 &,const String &,const String &,const String &)2008 bool XclExpLinkManagerImpl5::InsertDde(
2009         sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/,
2010         const String& /*rApplic*/, const String& /*rTopic*/, const String& /*rItem*/ )
2011 {
2012     // not implemented
2013     return false;
2014 }
2015 
InsertExtName(sal_uInt16 &,sal_uInt16 &,const String &,const String &,const ScExternalRefCache::TokenArrayRef)2016 bool XclExpLinkManagerImpl5::InsertExtName(
2017         sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rUrl*/,
2018         const String& /*rName*/, const ScExternalRefCache::TokenArrayRef /*pArray*/ )
2019 {
2020     // not implemented
2021     return false;
2022 }
2023 
Save(XclExpStream & rStrm)2024 void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
2025 {
2026     if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
2027     {
2028         // EXTERNCOUNT record
2029         XclExpUInt16Record( EXC_ID_EXTERNCOUNT, nExtSheetCount ).Save( rStrm );
2030         // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
2031         maExtSheetList.Save( rStrm );
2032     }
2033 }
2034 
GetExtSheetCount() const2035 sal_uInt16 XclExpLinkManagerImpl5::GetExtSheetCount() const
2036 {
2037     return static_cast< sal_uInt16 >( maExtSheetList.GetSize() );
2038 }
2039 
AppendInternal(XclExpExtSheetRef xExtSheet)2040 sal_uInt16 XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef xExtSheet )
2041 {
2042     if( GetExtSheetCount() < 0x7FFF )
2043     {
2044         maExtSheetList.AppendRecord( xExtSheet );
2045         // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
2046         return static_cast< sal_uInt16 >( -GetExtSheetCount() );
2047     }
2048     return 0;
2049 }
2050 
CreateInternal()2051 void XclExpLinkManagerImpl5::CreateInternal()
2052 {
2053     if( maIntTabMap.empty() )
2054     {
2055         // create EXTERNSHEET records for all internal exported sheets
2056         XclExpTabInfo& rTabInfo = GetTabInfo();
2057         for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
2058         {
2059             if( rTabInfo.IsExportTab( nScTab ) )
2060             {
2061                 XclExpExtSheetRef xRec;
2062                 if( nScTab == GetCurrScTab() )
2063                     xRec.reset( new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB ) );
2064                 else
2065                     xRec.reset( new XclExpExternSheet( GetRoot(), rTabInfo.GetScTabName( nScTab ) ) );
2066                 maIntTabMap[ nScTab ] = AppendInternal( xRec );
2067             }
2068         }
2069     }
2070 }
2071 
GetInternal(sal_uInt16 nExtSheet)2072 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet )
2073 {
2074     return maExtSheetList.GetRecord( static_cast< sal_uInt16 >( -nExtSheet - 1 ) );
2075 }
2076 
FindInternal(sal_uInt16 & rnExtSheet,sal_uInt16 & rnXclTab,SCTAB nScTab)2077 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
2078         sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab )
2079 {
2080     // create internal EXTERNSHEET records on demand
2081     CreateInternal();
2082 
2083     // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
2084     XclExpExtSheetRef xExtSheet;
2085     XclExpIntTabMap::const_iterator aIt = maIntTabMap.find( nScTab );
2086     if( aIt == maIntTabMap.end() )
2087     {
2088         xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_OWNDOC );
2089         rnXclTab = EXC_TAB_DELETED;
2090     }
2091     else
2092     {
2093         rnExtSheet = aIt->second;
2094         xExtSheet = GetInternal( rnExtSheet );
2095         rnXclTab = GetTabInfo().GetXclTab( nScTab );
2096     }
2097     return xExtSheet;
2098 }
2099 
FindInternal(sal_uInt16 & rnExtSheet,sal_Unicode cCode)2100 XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
2101     sal_uInt16& rnExtSheet, sal_Unicode cCode )
2102 {
2103     XclExpExtSheetRef xExtSheet;
2104     XclExpCodeMap::const_iterator aIt = maCodeMap.find( cCode );
2105     if( aIt == maCodeMap.end() )
2106     {
2107         xExtSheet.reset( new XclExpExternSheet( GetRoot(), cCode ) );
2108         rnExtSheet = maCodeMap[ cCode ] = AppendInternal( xExtSheet );
2109     }
2110     else
2111     {
2112         rnExtSheet = aIt->second;
2113         xExtSheet = GetInternal( rnExtSheet );
2114     }
2115     return xExtSheet;
2116 }
2117 
2118 // ----------------------------------------------------------------------------
2119 
XclExpLinkManagerImpl8(const XclExpRoot & rRoot)2120 XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot& rRoot ) :
2121     XclExpLinkManagerImpl( rRoot ),
2122     maSBBuffer( rRoot )
2123 {
2124 }
2125 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)2126 void XclExpLinkManagerImpl8::FindExtSheet(
2127         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
2128         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
2129 {
2130     XclExpTabInfo& rTabInfo = GetTabInfo();
2131     rnFirstXclTab = rTabInfo.GetXclTab( nFirstScTab );
2132     rnLastXclTab = rTabInfo.GetXclTab( nLastScTab );
2133     rnExtSheet = InsertXti( maSBBuffer.GetXti( rnFirstXclTab, rnLastXclTab, pRefLogEntry ) );
2134 }
2135 
FindExtSheet(sal_Unicode cCode)2136 sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
2137 {
2138     (void)cCode;    // avoid compiler warning
2139     DBG_ASSERT( (cCode == EXC_EXTSH_OWNDOC) || (cCode == EXC_EXTSH_ADDIN),
2140         "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
2141     return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2142 }
2143 
FindExtSheet(sal_uInt16 nFileId,const String & rTabName,sal_uInt16 nXclTabSpan,sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstSBTab,sal_uInt16 & rnLastSBTab,XclExpRefLogEntry * pRefLogEntry)2144 void XclExpLinkManagerImpl8::FindExtSheet(
2145     sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
2146     sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
2147     XclExpRefLogEntry* pRefLogEntry )
2148 {
2149     XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, pRefLogEntry);
2150     rnExtSheet = InsertXti(aXti);
2151     rnFirstSBTab = aXti.mnFirstSBTab;
2152     rnLastSBTab  = aXti.mnLastSBTab;
2153 }
2154 
StoreCellRange(const ScSingleRefData & rRef1,const ScSingleRefData & rRef2)2155 void XclExpLinkManagerImpl8::StoreCellRange( const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 )
2156 {
2157     if( !rRef1.IsDeleted() && !rRef2.IsDeleted() && (rRef1.nTab >= 0) && (rRef2.nTab >= 0) )
2158     {
2159         const XclExpTabInfo& rTabInfo = GetTabInfo();
2160         SCTAB nFirstScTab = static_cast< SCTAB >( rRef1.nTab );
2161         SCTAB nLastScTab = static_cast< SCTAB >( rRef2.nTab );
2162         ScRange aRange(
2163             static_cast< SCCOL >( rRef1.nCol ), static_cast< SCROW >( rRef1.nRow ), 0,
2164             static_cast< SCCOL >( rRef2.nCol ), static_cast< SCROW >( rRef2.nRow ), 0 );
2165         for( SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab )
2166         {
2167             if( rTabInfo.IsExternalTab( nScTab ) )
2168             {
2169                 aRange.aStart.SetTab( nScTab );
2170                 aRange.aEnd.SetTab( nScTab );
2171                 maSBBuffer.StoreCellRange( aRange );
2172             }
2173         }
2174     }
2175 }
2176 
StoreCell(sal_uInt16 nFileId,const String & rTabName,const ScSingleRefData & rRef)2177 void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
2178 {
2179     ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
2180     maSBBuffer.StoreCell(nFileId, rTabName, aAddr);
2181 }
2182 
StoreCellRange(sal_uInt16 nFileId,const String & rTabName,const ScSingleRefData & rRef1,const ScSingleRefData & rRef2)2183 void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 )
2184 {
2185     ScRange aRange(static_cast<SCCOL>(rRef1.nCol), static_cast<SCROW>(rRef1.nRow), static_cast<SCTAB>(rRef1.nTab),
2186                    static_cast<SCCOL>(rRef2.nCol), static_cast<SCROW>(rRef2.nRow), static_cast<SCTAB>(rRef2.nTab));
2187     maSBBuffer.StoreCellRange(nFileId, rTabName, aRange);
2188 }
2189 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName)2190 bool XclExpLinkManagerImpl8::InsertAddIn(
2191         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
2192 {
2193     sal_uInt16 nSupbook;
2194     if( maSBBuffer.InsertAddIn( nSupbook, rnExtName, rName ) )
2195     {
2196         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2197         return true;
2198     }
2199     return false;
2200 }
2201 
InsertEuroTool(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName)2202 bool XclExpLinkManagerImpl8::InsertEuroTool(
2203          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
2204 {
2205     sal_uInt16 nSupbook;
2206     if( maSBBuffer.InsertEuroTool( nSupbook, rnExtName, rName ) )
2207     {
2208         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2209         return true;
2210     }
2211     return false;
2212 }
2213 
2214 
InsertDde(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rApplic,const String & rTopic,const String & rItem)2215 bool XclExpLinkManagerImpl8::InsertDde(
2216         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2217         const String& rApplic, const String& rTopic, const String& rItem )
2218 {
2219     sal_uInt16 nSupbook;
2220     if( maSBBuffer.InsertDde( nSupbook, rnExtName, rApplic, rTopic, rItem ) )
2221     {
2222         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2223         return true;
2224     }
2225     return false;
2226 }
2227 
InsertExtName(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName,const String & rUrl,const ScExternalRefCache::TokenArrayRef pArray)2228 bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2229         const String& rName, const String& rUrl, const ScExternalRefCache::TokenArrayRef pArray )
2230 {
2231     sal_uInt16 nSupbook;
2232     if( maSBBuffer.InsertExtName( nSupbook, rnExtName, rUrl, rName, pArray ) )
2233     {
2234         rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
2235         return true;
2236     }
2237     return false;
2238 }
2239 
Save(XclExpStream & rStrm)2240 void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
2241 {
2242     if( !maXtiVec.empty() )
2243     {
2244         // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
2245         maSBBuffer.Save( rStrm );
2246 
2247         // EXTERNSHEET
2248         sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXtiVec.size() );
2249         rStrm.StartRecord( EXC_ID_EXTERNSHEET, 2 + 6 * nCount );
2250         rStrm << nCount;
2251         rStrm.SetSliceSize( 6 );
2252         for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
2253             aIt->Save( rStrm );
2254         rStrm.EndRecord();
2255     }
2256 }
2257 
InsertXti(const XclExpXti & rXti)2258 sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
2259 {
2260     for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
2261         if( *aIt == rXti )
2262             return ulimit_cast< sal_uInt16 >( aIt - maXtiVec.begin() );
2263     maXtiVec.push_back( rXti );
2264     return ulimit_cast< sal_uInt16 >( maXtiVec.size() - 1 );
2265 }
2266 
2267 // ============================================================================
2268 
XclExpLinkManager(const XclExpRoot & rRoot)2269 XclExpLinkManager::XclExpLinkManager( const XclExpRoot& rRoot ) :
2270     XclExpRoot( rRoot )
2271 {
2272     switch( GetBiff() )
2273     {
2274         case EXC_BIFF5:
2275             mxImpl.reset( new XclExpLinkManagerImpl5( rRoot ) );
2276         break;
2277         case EXC_BIFF8:
2278             mxImpl.reset( new XclExpLinkManagerImpl8( rRoot ) );
2279         break;
2280         default:
2281             DBG_ERROR_BIFF();
2282     }
2283 }
2284 
~XclExpLinkManager()2285 XclExpLinkManager::~XclExpLinkManager()
2286 {
2287 }
2288 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnXclTab,SCTAB nScTab,XclExpRefLogEntry * pRefLogEntry)2289 void XclExpLinkManager::FindExtSheet(
2290         sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab,
2291         SCTAB nScTab, XclExpRefLogEntry* pRefLogEntry )
2292 {
2293     mxImpl->FindExtSheet( rnExtSheet, rnXclTab, rnXclTab, nScTab, nScTab, pRefLogEntry );
2294 }
2295 
FindExtSheet(sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstXclTab,sal_uInt16 & rnLastXclTab,SCTAB nFirstScTab,SCTAB nLastScTab,XclExpRefLogEntry * pRefLogEntry)2296 void XclExpLinkManager::FindExtSheet(
2297         sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
2298         SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
2299 {
2300     mxImpl->FindExtSheet( rnExtSheet, rnFirstXclTab, rnLastXclTab, nFirstScTab, nLastScTab, pRefLogEntry );
2301 }
2302 
FindExtSheet(sal_Unicode cCode)2303 sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
2304 {
2305     return mxImpl->FindExtSheet( cCode );
2306 }
2307 
FindExtSheet(sal_uInt16 nFileId,const String & rTabName,sal_uInt16 nXclTabSpan,sal_uInt16 & rnExtSheet,sal_uInt16 & rnFirstSBTab,sal_uInt16 & rnLastSBTab,XclExpRefLogEntry * pRefLogEntry)2308 void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
2309                                       sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
2310                                       XclExpRefLogEntry* pRefLogEntry )
2311 {
2312     mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry );
2313 }
2314 
StoreCell(const ScSingleRefData & rRef)2315 void XclExpLinkManager::StoreCell( const ScSingleRefData& rRef )
2316 {
2317     mxImpl->StoreCellRange( rRef, rRef );
2318 }
2319 
StoreCellRange(const ScComplexRefData & rRef)2320 void XclExpLinkManager::StoreCellRange( const ScComplexRefData& rRef )
2321 {
2322     mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
2323 }
2324 
StoreCell(sal_uInt16 nFileId,const String & rTabName,const ScSingleRefData & rRef)2325 void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
2326 {
2327     mxImpl->StoreCell( nFileId, rTabName, rRef );
2328 }
2329 
StoreCellRange(sal_uInt16 nFileId,const String & rTabName,const ScComplexRefData & rRef)2330 void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
2331 {
2332     mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 );
2333 }
2334 
InsertAddIn(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName)2335 bool XclExpLinkManager::InsertAddIn(
2336         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
2337 {
2338     return mxImpl->InsertAddIn( rnExtSheet, rnExtName, rName );
2339 }
2340 
InsertEuroTool(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName)2341 bool XclExpLinkManager::InsertEuroTool(
2342         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
2343 {
2344     return mxImpl->InsertEuroTool( rnExtSheet, rnExtName, rName );
2345 }
2346 
InsertDde(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rApplic,const String & rTopic,const String & rItem)2347 bool XclExpLinkManager::InsertDde(
2348         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
2349         const String& rApplic, const String& rTopic, const String& rItem )
2350 {
2351     return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
2352 }
2353 
InsertExtName(sal_uInt16 & rnExtSheet,sal_uInt16 & rnExtName,const String & rName,const String & rUrl,const ScExternalRefCache::TokenArrayRef pArray)2354 bool XclExpLinkManager::InsertExtName(
2355     sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl,
2356     const ScExternalRefCache::TokenArrayRef pArray )
2357 {
2358     return mxImpl->InsertExtName( rnExtSheet, rnExtName, rUrl, rName, pArray );
2359 }
2360 
Save(XclExpStream & rStrm)2361 void XclExpLinkManager::Save( XclExpStream& rStrm )
2362 {
2363     mxImpl->Save( rStrm );
2364 }
2365 
2366 // ============================================================================
2367 
2368