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_sc.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