xref: /aoo41x/main/sc/source/filter/excel/xilink.cxx (revision b3f79822)
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 "xilink.hxx"
27 #include "document.hxx"
28 #include "cell.hxx"
29 #include "scextopt.hxx"
30 #include "tablink.hxx"
31 #include "xistream.hxx"
32 #include "xihelper.hxx"
33 #include "xiname.hxx"
34 #include "excform.hxx"
35 #include "tokenarray.hxx"
36 #include "externalrefmgr.hxx"
37 
38 #include <vector>
39 
40 using ::std::vector;
41 
42 // ============================================================================
43 // *** Helper classes ***
44 // ============================================================================
45 
46 // Cached external cells ======================================================
47 
48 /** Contains the address and value of an external referenced cell. */
49 class XclImpCrn : public XclImpCachedValue
50 {
51 public:
52     /** Reads a cached value and stores it with its cell address. */
53     explicit            XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
54 
55     const XclAddress&   GetAddress() const;
56 
57 private:
58     XclAddress          maXclPos;       /// Excel position of the cached cell.
59 };
60 
61 // Sheet in an external document ==============================================
62 
63 /** Contains the name and sheet index of one sheet in an external document. */
64 class XclImpSupbookTab
65 {
66 public:
67     /** Stores the sheet name and marks the sheet index as invalid.
68         The sheet index is set while creating the Calc sheet with CreateTable(). */
69     explicit            XclImpSupbookTab( const String& rTabName );
70                         ~XclImpSupbookTab();
71 
GetTabName() const72     inline const String& GetTabName() const { return maTabName; }
73 
74     /** Reads a CRN record (external referenced cell) at the specified address. */
75     void                ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
76 
77     void                LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable);
78 
79 private:
80     typedef ScfDelList< XclImpCrn > XclImpCrnList;
81 
82     XclImpCrnList       maCrnList;      /// List of CRN records (cached cell values).
83     String              maTabName;      /// Name of the external sheet.
84     SCTAB               mnScTab;        /// New sheet index in Calc document.
85 };
86 
87 // External document (SUPBOOK) ================================================
88 
89 /** This class represents an external linked document (record SUPBOOK).
90     @descr  Contains a list of all referenced sheets in the document. */
91 class XclImpSupbook : protected XclImpRoot
92 {
93 public:
94     /** Reads the SUPBOOK record from stream. */
95     explicit            XclImpSupbook( XclImpStream& rStrm );
96 
97     /** Reads an XCT record (count of following CRNs and current sheet). */
98     void                ReadXct( XclImpStream& rStrm );
99     /** Reads a CRN record (external referenced cell). */
100     void                ReadCrn( XclImpStream& rStrm );
101     /** Reads an EXTERNNAME record. */
102     void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
103 
104     /** Returns the SUPBOOK record type. */
GetType() const105     inline XclSupbookType GetType() const { return meType; }
106 
107     /** Returns the URL of the external document. */
GetXclUrl() const108     inline const String& GetXclUrl() const { return maXclUrl; }
109 
110     /** Returns the external name specified by an index from the Excel document (one-based). */
111     const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
112     /** Tries to decode the URL to OLE or DDE link components.
113         @descr  For DDE links: Decodes to application name and topic.
114         For OLE object links: Decodes to class name and document URL.
115         @return  true = decoding was successful, returned strings are valid (not empty). */
116     bool                GetLinkData( String& rApplic, String& rDoc ) const;
117     /** Returns the specified macro name (1-based) or an empty string on error. */
118     const String&       GetMacroName( sal_uInt16 nXclNameIdx ) const;
119 
120     const String&       GetTabName( sal_uInt16 nXtiTab ) const;
121 
122     sal_uInt16          GetTabCount() const;
123 
124     void                LoadCachedValues();
125 
126 private:
127     typedef ScfDelList< XclImpSupbookTab >  XclImpSupbookTabList;
128     typedef ScfDelList< XclImpExtName >     XclImpExtNameList;
129 
130     XclImpSupbookTabList maSupbTabList;     /// All sheet names of the document.
131     XclImpExtNameList   maExtNameList;      /// All external names of the document.
132     String              maXclUrl;           /// URL of the external document (Excel mode).
133     String              maFilterName;       /// Detected filer name.
134     String              maFilterOpt;        /// Detected filer options.
135     XclSupbookType      meType;             /// Type of the supbook record.
136     sal_uInt16          mnSBTab;            /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
137 };
138 
139 // Import link manager ========================================================
140 
141 /** Contains the SUPBOOK index and sheet indexes of an external link.
142     @descr  It is possible to enter a formula like =SUM(Sheet1:Sheet3!A1),
143     therefore here occurs a sheet range. */
144 struct XclImpXti
145 {
146     sal_uInt16          mnSupbook;      /// Index to SUPBOOK record.
147     sal_uInt16          mnSBTabFirst;   /// Index to the first sheet of the range in the SUPBOOK.
148     sal_uInt16          mnSBTabLast;    /// Index to the last sheet of the range in the SUPBOOK.
XclImpXtiXclImpXti149     inline explicit     XclImpXti() : mnSupbook( SAL_MAX_UINT16 ), mnSBTabFirst( SAL_MAX_UINT16 ), mnSBTabLast( SAL_MAX_UINT16 ) {}
150 };
151 
operator >>(XclImpStream & rStrm,XclImpXti & rXti)152 inline XclImpStream& operator>>( XclImpStream& rStrm, XclImpXti& rXti )
153 {
154     return rStrm >> rXti.mnSupbook >> rXti.mnSBTabFirst >> rXti.mnSBTabLast;
155 }
156 
157 // ----------------------------------------------------------------------------
158 
159 /** Implementation of the link manager. */
160 class XclImpLinkManagerImpl : protected XclImpRoot
161 {
162 public:
163     explicit            XclImpLinkManagerImpl( const XclImpRoot& rRoot );
164 
165     /** Reads the EXTERNSHEET record. */
166     void                ReadExternsheet( XclImpStream& rStrm );
167     /** Reads a SUPBOOK record. */
168     void                ReadSupbook( XclImpStream& rStrm );
169     /** Reads an XCT record and appends it to the current SUPBOOK. */
170     void                ReadXct( XclImpStream& rStrm );
171     /** Reads a CRN record and appends it to the current SUPBOOK. */
172     void                ReadCrn( XclImpStream& rStrm );
173     /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
174     void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
175 
176     /** Returns true, if the specified XTI entry contains an internal reference. */
177     bool                IsSelfRef( sal_uInt16 nXtiIndex ) const;
178     /** Returns the Calc sheet index range of the specified XTI entry.
179         @return  true = XTI data found, returned sheet index range is valid. */
180     bool                GetScTabRange(
181                             SCTAB& rnFirstScTab, SCTAB& rnLastScTab,
182                             sal_uInt16 nXtiIndex ) const;
183     /** Returns the specified external name or 0 on error. */
184     const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
185 
186     /** Returns the absolute file URL of a supporting workbook specified by
187         the index. */
188     const String*       GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
189 
190     const String&       GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
191 
192     /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
193         @descr  For DDE links: Decodes to application name and topic.
194         For OLE object links: Decodes to class name and document URL.
195         @return  true = decoding was successful, returned strings are valid (not empty). */
196     bool                GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const;
197     /** Returns the specified macro name or an empty string on error. */
198     const String&       GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
199 
200 private:
201     /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
202     const XclImpXti*    GetXti( sal_uInt16 nXtiIndex ) const;
203     /** Returns the specified SUPBOOK (external document). */
204     const XclImpSupbook* GetSupbook( sal_uInt16 nXtiIndex ) const;
205 //UNUSED2009-05 /** Returns the SUPBOOK (external workbook) specified by its URL. */
206 //UNUSED2009-05 const XclImpSupbook* GetSupbook( const String& rUrl ) const;
207 
208     void                LoadCachedValues();
209 
210 //UNUSED2009-05 /** Finds the largest range of sheet indexes in a SUPBOOK after a start sheet index.
211 //UNUSED2009-05     @param rnSBTabFirst  (out-param) The first sheet index of the range in SUPBOOK is returned here.
212 //UNUSED2009-05     @param rnSBTabLast  (out-param) The last sheet index of the range in SUPBOOK is returned here (inclusive).
213 //UNUSED2009-05     @param nSupbook  The list index of the SUPBOOK.
214 //UNUSED2009-05     @param nSBTabStart  The first allowed sheet index. Sheet ranges with an earlier start index are ignored.
215 //UNUSED2009-05     @return  true = the return values are valid; false = nothing found. */
216 //UNUSED2009-05 bool                FindNextTabRange(
217 //UNUSED2009-05                         sal_uInt16& rnSBTabFirst, sal_uInt16& rnSBTabLast,
218 //UNUSED2009-05                         sal_uInt16 nSupbook, sal_uInt16 nSBTabStart ) const;
219 
220 private:
221     typedef ::std::vector< XclImpXti >  XclImpXtiVector;
222     typedef ScfDelList< XclImpSupbook > XclImpSupbookList;
223 
224     XclImpXtiVector     maXtiList;          /// List of all XTI structures.
225     XclImpSupbookList   maSupbookList;      /// List of external documents.
226     bool                mbCreated;          /// true = Calc sheets already created.
227 };
228 
229 // ============================================================================
230 // *** Implementation ***
231 // ============================================================================
232 
233 // Excel sheet indexes ========================================================
234 
235 // original Excel sheet names -------------------------------------------------
236 
AppendXclTabName(const String & rXclTabName,SCTAB nScTab)237 void XclImpTabInfo::AppendXclTabName( const String& rXclTabName, SCTAB nScTab )
238 {
239     maTabNames[ rXclTabName ] = nScTab;
240 }
241 
InsertScTab(SCTAB nScTab)242 void XclImpTabInfo::InsertScTab( SCTAB nScTab )
243 {
244     for( XclTabNameMap::iterator aIt = maTabNames.begin(), aEnd = maTabNames.end(); aIt != aEnd; ++aIt )
245         if( aIt->second >= nScTab )
246             ++aIt->second;
247 }
248 
GetScTabFromXclName(const String & rXclTabName) const249 SCTAB XclImpTabInfo::GetScTabFromXclName( const String& rXclTabName ) const
250 {
251     XclTabNameMap::const_iterator aIt = maTabNames.find( rXclTabName );
252     return (aIt != maTabNames.end()) ? aIt->second : SCTAB_INVALID;
253 }
254 
255 // record creation order - TABID record ---------------------------------------
256 
ReadTabid(XclImpStream & rStrm)257 void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
258 {
259     DBG_ASSERT_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
260     if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
261     {
262         rStrm.EnableDecryption();
263         sal_Size nReadCount = rStrm.GetRecLeft() / 2;
264         DBG_ASSERT( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
265         maTabIdVec.clear();
266         maTabIdVec.reserve( nReadCount );
267         for( sal_Size nIndex = 0; rStrm.IsValid() && (nIndex < nReadCount); ++nIndex )
268             // #93471# zero index is not allowed in BIFF8, but it seems that it occurs in real life
269             maTabIdVec.push_back( rStrm.ReaduInt16() );
270     }
271 }
272 
GetCurrentIndex(sal_uInt16 nCreatedId,sal_uInt16 nMaxTabId) const273 sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMaxTabId ) const
274 {
275     sal_uInt16 nReturn = 0;
276     for( ScfUInt16Vec::const_iterator aIt = maTabIdVec.begin(), aEnd = maTabIdVec.end(); aIt != aEnd; ++aIt )
277     {
278         sal_uInt16 nValue = *aIt;
279         if( nValue == nCreatedId )
280             return nReturn;
281         if( nValue <= nMaxTabId )
282             ++nReturn;
283     }
284     return 0;
285 }
286 
287 // External names =============================================================
288 
XclImpExtName(const XclImpSupbook & rSupbook,XclImpStream & rStrm,XclSupbookType eSubType,ExcelToSc * pFormulaConv)289 XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv )
290 {
291     sal_uInt16 nFlags;
292     sal_uInt8 nLen;
293 
294     rStrm >> nFlags >> mnStorageId >> nLen ;
295     maName = rStrm.ReadUniString( nLen );
296     if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
297     {
298         if( eSubType == EXC_SBTYPE_ADDIN )
299         {
300             meType = xlExtAddIn;
301             maName = rStrm.GetRoot().GetScAddInName( maName );
302         }
303         else if ( (eSubType == EXC_SBTYPE_EUROTOOL) &&
304                 maName.EqualsIgnoreCaseAscii( "EUROCONVERT" ) )
305             meType = xlExtEuroConvert;
306         else
307         {
308             meType = xlExtName;
309             ScfTools::ConvertToScDefinedName( maName );
310         }
311     }
312     else
313     {
314         meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
315     }
316 
317     if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) )
318         mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) );
319 
320     if (meType == xlExtName)
321     {
322         // TODO: For now, only global external names are supported.  In future
323         // we should extend this to supporting per-sheet external names.
324         if (mnStorageId == 0)
325         {
326             if (pFormulaConv)
327             {
328                 const ScTokenArray* pArray = NULL;
329                 sal_uInt16 nFmlaLen;
330                 rStrm >> nFmlaLen;
331                 vector<String> aTabNames;
332                 sal_uInt16 nCount = rSupbook.GetTabCount();
333                 aTabNames.reserve(nCount);
334                 for (sal_uInt16 i = 0; i < nCount; ++i)
335                     aTabNames.push_back(rSupbook.GetTabName(i));
336 
337                 pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
338                 if (pArray)
339                     mxArray.reset(pArray->Clone());
340             }
341         }
342     }
343 }
344 
~XclImpExtName()345 XclImpExtName::~XclImpExtName()
346 {
347 }
348 
CreateDdeData(ScDocument & rDoc,const String & rApplic,const String & rTopic) const349 void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const
350 {
351     ScMatrixRef xResults;
352     if( mxDdeMatrix.get() )
353         xResults = mxDdeMatrix->CreateScMatrix();
354     rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
355 }
356 
CreateExtNameData(ScDocument & rDoc,sal_uInt16 nFileId) const357 void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
358 {
359     if (!mxArray.get())
360         return;
361 
362     ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
363     pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
364 }
365 
HasFormulaTokens() const366 bool XclImpExtName::HasFormulaTokens() const
367 {
368     return (mxArray.get() != NULL);
369 }
370 
371 // Cached external cells ======================================================
372 
XclImpCrn(XclImpStream & rStrm,const XclAddress & rXclPos)373 XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
374     XclImpCachedValue( rStrm ),
375     maXclPos( rXclPos )
376 {
377 }
378 
GetAddress() const379 const XclAddress& XclImpCrn::GetAddress() const
380 {
381     return maXclPos;
382 }
383 
384 // Sheet in an external document ==============================================
385 
XclImpSupbookTab(const String & rTabName)386 XclImpSupbookTab::XclImpSupbookTab( const String& rTabName ) :
387     maTabName( rTabName ),
388     mnScTab( SCTAB_INVALID )
389 {
390 }
391 
~XclImpSupbookTab()392 XclImpSupbookTab::~XclImpSupbookTab()
393 {
394 }
395 
ReadCrn(XclImpStream & rStrm,const XclAddress & rXclPos)396 void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
397 {
398     maCrnList.Append( new XclImpCrn( rStrm, rXclPos ) );
399 }
400 
LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable)401 void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable)
402 {
403     if (maCrnList.Empty())
404         return;
405 
406     for (XclImpCrn* p = maCrnList.First(); p; p = maCrnList.Next())
407     {
408         const XclAddress& rAddr = p->GetAddress();
409         switch (p->GetType())
410         {
411             case EXC_CACHEDVAL_BOOL:
412             {
413                 bool b = p->GetBool();
414                 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
415                 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken);
416             }
417             break;
418             case EXC_CACHEDVAL_DOUBLE:
419             {
420                 double f = p->GetValue();
421                 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(f));
422                 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken);
423             }
424             break;
425             case EXC_CACHEDVAL_ERROR:
426             {
427                 double fError = XclTools::ErrorToDouble( p->GetXclError() );
428                 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(fError));
429                 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken);
430             }
431             break;
432             case EXC_CACHEDVAL_STRING:
433             {
434                 const String& rStr = p->GetString();
435                 ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
436                 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken);
437             }
438             break;
439             default:
440                 ;
441         }
442     }
443 }
444 
445 // External document (SUPBOOK) ================================================
446 
XclImpSupbook(XclImpStream & rStrm)447 XclImpSupbook::XclImpSupbook( XclImpStream& rStrm ) :
448     XclImpRoot( rStrm.GetRoot() ),
449     meType( EXC_SBTYPE_UNKNOWN ),
450     mnSBTab( EXC_TAB_DELETED )
451 {
452     sal_uInt16 nSBTabCnt;
453     rStrm >> nSBTabCnt;
454 
455     if( rStrm.GetRecLeft() == 2 )
456     {
457         switch( rStrm.ReaduInt16() )
458         {
459             case EXC_SUPB_SELF:     meType = EXC_SBTYPE_SELF;   break;
460             case EXC_SUPB_ADDIN:    meType = EXC_SBTYPE_ADDIN;  break;
461             default:    DBG_ERRORFILE( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
462         }
463         return;
464     }
465 
466     String aEncUrl( rStrm.ReadUniString() );
467     bool bSelf = false;
468     XclImpUrlHelper::DecodeUrl( maXclUrl, bSelf, GetRoot(), aEncUrl );
469 
470     if( maXclUrl.EqualsIgnoreCaseAscii( "\010EUROTOOL.XLA" ) )
471     {
472         meType = EXC_SBTYPE_EUROTOOL;
473         maSupbTabList.Append( new XclImpSupbookTab( maXclUrl ) );
474     }
475     else if( nSBTabCnt )
476     {
477         meType = EXC_SBTYPE_EXTERN;
478         for( sal_uInt16 nSBTab = 0; nSBTab < nSBTabCnt; ++nSBTab )
479         {
480             String aTabName( rStrm.ReadUniString() );
481             maSupbTabList.Append( new XclImpSupbookTab( aTabName ) );
482         }
483     }
484     else
485     {
486         meType = EXC_SBTYPE_SPECIAL;
487         // create dummy list entry
488         maSupbTabList.Append( new XclImpSupbookTab( maXclUrl ) );
489     }
490 }
491 
ReadXct(XclImpStream & rStrm)492 void XclImpSupbook::ReadXct( XclImpStream& rStrm )
493 {
494     rStrm.Ignore( 2 );
495     rStrm >> mnSBTab;
496 }
497 
ReadCrn(XclImpStream & rStrm)498 void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
499 {
500     if( XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( mnSBTab ) )
501     {
502         sal_uInt8 nXclColLast, nXclColFirst;
503         sal_uInt16 nXclRow;
504         rStrm >> nXclColLast >> nXclColFirst >> nXclRow;
505 
506         for( sal_uInt8 nXclCol = nXclColFirst; (nXclCol <= nXclColLast) && (rStrm.GetRecLeft() > 1); ++nXclCol )
507             pSBTab->ReadCrn( rStrm, XclAddress( nXclCol, nXclRow ) );
508     }
509 }
510 
ReadExternname(XclImpStream & rStrm,ExcelToSc * pFormulaConv)511 void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
512 {
513     maExtNameList.Append( new XclImpExtName( *this, rStrm, meType, pFormulaConv ) );
514 }
515 
GetExternName(sal_uInt16 nXclIndex) const516 const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
517 {
518     DBG_ASSERT( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" );
519     return (meType == EXC_SBTYPE_SELF) ? 0 : maExtNameList.GetObject( nXclIndex - 1 );
520 }
521 
GetLinkData(String & rApplic,String & rTopic) const522 bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const
523 {
524     return (meType == EXC_SBTYPE_SPECIAL) && XclImpUrlHelper::DecodeLink( rApplic, rTopic, maXclUrl );
525 }
526 
GetMacroName(sal_uInt16 nXclNameIdx) const527 const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
528 {
529     DBG_ASSERT( nXclNameIdx > 0, "XclImpSupbook::GetMacroName - index must be >0" );
530     const XclImpName* pName = (meType == EXC_SBTYPE_SELF) ? GetNameManager().GetName( nXclNameIdx ) : 0;
531     return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
532 }
533 
GetTabName(sal_uInt16 nXtiTab) const534 const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
535 {
536     if (maSupbTabList.Empty())
537         return EMPTY_STRING;
538 
539     sal_uInt16 i = 0;
540     for (XclImpSupbookTab* p = maSupbTabList.First(); p; p = maSupbTabList.Next(), ++i)
541     {
542         if (i == nXtiTab)
543             return p->GetTabName();
544     }
545 
546     return EMPTY_STRING;
547 }
548 
GetTabCount() const549 sal_uInt16 XclImpSupbook::GetTabCount() const
550 {
551     return ulimit_cast<sal_uInt16>(maSupbTabList.Count());
552 }
553 
LoadCachedValues()554 void XclImpSupbook::LoadCachedValues()
555 {
556     if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0 || !GetDocShell())
557         return;
558 
559     String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
560 
561     ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
562     sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
563 
564     sal_uInt16 nCount = static_cast< sal_uInt16 >( maSupbTabList.Count() );
565     for (sal_uInt16 i = 0; i < nCount; ++i)
566     {
567         XclImpSupbookTab* pTab = maSupbTabList.GetObject(i);
568         if (!pTab)
569             return;
570 
571         const String& rTabName = pTab->GetTabName();
572         ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
573         pTab->LoadCachedValues(pCacheTable);
574         pCacheTable->setWholeTableCached();
575     }
576 }
577 
578 // Import link manager ========================================================
579 
XclImpLinkManagerImpl(const XclImpRoot & rRoot)580 XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot& rRoot ) :
581     XclImpRoot( rRoot ),
582     mbCreated( false )
583 {
584 }
585 
ReadExternsheet(XclImpStream & rStrm)586 void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
587 {
588     sal_uInt16 nXtiCount;
589     rStrm >> nXtiCount;
590     DBG_ASSERT( static_cast< sal_Size >( nXtiCount * 6 ) == rStrm.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
591     nXtiCount = static_cast< sal_uInt16 >( ::std::min< sal_Size >( nXtiCount, rStrm.GetRecLeft() / 6 ) );
592 
593     /*  #i104057# A weird external XLS generator writes multiple EXTERNSHEET
594         records instead of only one as expected. Surprisingly, Excel seems to
595         insert the entries of the second record before the entries of the first
596         record. */
597     XclImpXtiVector aNewEntries( nXtiCount );
598     for( XclImpXtiVector::iterator aIt = aNewEntries.begin(), aEnd = aNewEntries.end(); rStrm.IsValid() && (aIt != aEnd); ++aIt )
599         rStrm >> *aIt;
600     maXtiList.insert( maXtiList.begin(), aNewEntries.begin(), aNewEntries.end() );
601 
602     LoadCachedValues();
603 }
604 
ReadSupbook(XclImpStream & rStrm)605 void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
606 {
607     maSupbookList.Append( new XclImpSupbook( rStrm ) );
608 }
609 
ReadXct(XclImpStream & rStrm)610 void XclImpLinkManagerImpl::ReadXct( XclImpStream& rStrm )
611 {
612     if( XclImpSupbook* pSupbook = maSupbookList.Last() )
613         pSupbook->ReadXct( rStrm );
614 }
615 
ReadCrn(XclImpStream & rStrm)616 void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
617 {
618     if( XclImpSupbook* pSupbook = maSupbookList.Last() )
619         pSupbook->ReadCrn( rStrm );
620 }
621 
ReadExternname(XclImpStream & rStrm,ExcelToSc * pFormulaConv)622 void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
623 {
624     if( XclImpSupbook* pSupbook = maSupbookList.Last() )
625         pSupbook->ReadExternname( rStrm, pFormulaConv );
626 }
627 
IsSelfRef(sal_uInt16 nXtiIndex) const628 bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
629 {
630     const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
631     return pSupbook && (pSupbook->GetType() == EXC_SBTYPE_SELF);
632 }
633 
GetScTabRange(SCTAB & rnFirstScTab,SCTAB & rnLastScTab,sal_uInt16 nXtiIndex) const634 bool XclImpLinkManagerImpl::GetScTabRange(
635         SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
636 {
637     if( const XclImpXti* pXti = GetXti( nXtiIndex ) )
638     {
639         if (maSupbookList.GetObject(pXti->mnSupbook))
640         {
641             rnFirstScTab = pXti->mnSBTabFirst;
642             rnLastScTab  = pXti->mnSBTabLast;
643             return true;
644         }
645     }
646     return false;
647 }
648 
GetExternName(sal_uInt16 nXtiIndex,sal_uInt16 nExtName) const649 const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
650 {
651     const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
652     return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
653 }
654 
GetSupbookUrl(sal_uInt16 nXtiIndex) const655 const String* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
656 {
657     const XclImpSupbook* p = GetSupbook( nXtiIndex );
658     if (!p)
659         return NULL;
660     return &p->GetXclUrl();
661 }
662 
GetSupbookTabName(sal_uInt16 nXti,sal_uInt16 nXtiTab) const663 const String& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
664 {
665     const XclImpSupbook* p = GetSupbook(nXti);
666     return p ? p->GetTabName(nXtiTab) : EMPTY_STRING;
667 }
668 
GetLinkData(String & rApplic,String & rTopic,sal_uInt16 nXtiIndex) const669 bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
670 {
671     const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
672     return pSupbook && pSupbook->GetLinkData( rApplic, rTopic );
673 }
674 
GetMacroName(sal_uInt16 nExtSheet,sal_uInt16 nExtName) const675 const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
676 {
677     const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
678     return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
679 }
680 
GetXti(sal_uInt16 nXtiIndex) const681 const XclImpXti* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex ) const
682 {
683     return (nXtiIndex < maXtiList.size()) ? &maXtiList[ nXtiIndex ] : 0;
684 }
685 
GetSupbook(sal_uInt16 nXtiIndex) const686 const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex ) const
687 {
688     const XclImpXti* pXti = GetXti( nXtiIndex );
689     return pXti ? maSupbookList.GetObject( pXti->mnSupbook ) : 0;
690 }
691 
692 //UNUSED2009-05 const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) const
693 //UNUSED2009-05 {
694 //UNUSED2009-05     for( const XclImpSupbook* pSupbook = maSupbookList.First(); pSupbook; pSupbook = maSupbookList.Next() )
695 //UNUSED2009-05         if( pSupbook->GetXclUrl() == rUrl )
696 //UNUSED2009-05             return pSupbook;
697 //UNUSED2009-05     return 0;
698 //UNUSED2009-05 }
699 
LoadCachedValues()700 void XclImpLinkManagerImpl::LoadCachedValues()
701 {
702     // Read all CRN records which can be accessed via XclImpSupbook, and store
703     // the cached values to the external reference manager.
704 
705     sal_uInt32 nCount = maSupbookList.Count();
706     for (sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook)
707     {
708         XclImpSupbook* pSupbook = maSupbookList.GetObject(nSupbook);
709         pSupbook->LoadCachedValues();
710     }
711 }
712 
713 //UNUSED2009-05 bool XclImpLinkManagerImpl::FindNextTabRange(
714 //UNUSED2009-05         sal_uInt16& rnSBTabFirst, sal_uInt16& rnSBTabLast,
715 //UNUSED2009-05         sal_uInt16 nSupbook, sal_uInt16 nSBTabStart ) const
716 //UNUSED2009-05 {
717 //UNUSED2009-05     rnSBTabFirst = rnSBTabLast = EXC_NOTAB;
718 //UNUSED2009-05     for( const XclImpXti* pXti = maXtiList.First(); pXti; pXti = maXtiList.Next() )
719 //UNUSED2009-05     {
720 //UNUSED2009-05         if( (nSupbook == pXti->mnSupbook) && (nSBTabStart <= pXti->mnSBTabLast) && (pXti->mnSBTabFirst < rnSBTabFirst) )
721 //UNUSED2009-05         {
722 //UNUSED2009-05             rnSBTabFirst = ::std::max( nSBTabStart, pXti->mnSBTabFirst );
723 //UNUSED2009-05             rnSBTabLast = pXti->mnSBTabLast;
724 //UNUSED2009-05         }
725 //UNUSED2009-05     }
726 //UNUSED2009-05     return rnSBTabFirst != EXC_NOTAB;
727 //UNUSED2009-05 }
728 
729 // ============================================================================
730 
XclImpLinkManager(const XclImpRoot & rRoot)731 XclImpLinkManager::XclImpLinkManager( const XclImpRoot& rRoot ) :
732     XclImpRoot( rRoot ),
733     mxImpl( new XclImpLinkManagerImpl( rRoot ) )
734 {
735 }
736 
~XclImpLinkManager()737 XclImpLinkManager::~XclImpLinkManager()
738 {
739 }
740 
ReadExternsheet(XclImpStream & rStrm)741 void XclImpLinkManager::ReadExternsheet( XclImpStream& rStrm )
742 {
743     mxImpl->ReadExternsheet( rStrm );
744 }
745 
ReadSupbook(XclImpStream & rStrm)746 void XclImpLinkManager::ReadSupbook( XclImpStream& rStrm )
747 {
748     mxImpl->ReadSupbook( rStrm );
749 }
750 
ReadXct(XclImpStream & rStrm)751 void XclImpLinkManager::ReadXct( XclImpStream& rStrm )
752 {
753     mxImpl->ReadXct( rStrm );
754 }
755 
ReadCrn(XclImpStream & rStrm)756 void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
757 {
758     mxImpl->ReadCrn( rStrm );
759 }
760 
ReadExternname(XclImpStream & rStrm,ExcelToSc * pFormulaConv)761 void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
762 {
763     mxImpl->ReadExternname( rStrm, pFormulaConv );
764 }
765 
IsSelfRef(sal_uInt16 nXtiIndex) const766 bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
767 {
768     return mxImpl->IsSelfRef( nXtiIndex );
769 }
770 
GetScTabRange(SCTAB & rnFirstScTab,SCTAB & rnLastScTab,sal_uInt16 nXtiIndex) const771 bool XclImpLinkManager::GetScTabRange(
772         SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
773 {
774     return mxImpl->GetScTabRange( rnFirstScTab, rnLastScTab, nXtiIndex );
775 }
776 
GetExternName(sal_uInt16 nXtiIndex,sal_uInt16 nExtName) const777 const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
778 {
779     return mxImpl->GetExternName( nXtiIndex, nExtName );
780 }
781 
GetSupbookUrl(sal_uInt16 nXtiIndex) const782 const String* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
783 {
784     return mxImpl->GetSupbookUrl(nXtiIndex);
785 }
786 
GetSupbookTabName(sal_uInt16 nXti,sal_uInt16 nXtiTab) const787 const String& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti,  sal_uInt16 nXtiTab ) const
788 {
789     return mxImpl->GetSupbookTabName(nXti, nXtiTab);
790 }
791 
GetLinkData(String & rApplic,String & rTopic,sal_uInt16 nXtiIndex) const792 bool XclImpLinkManager::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
793 {
794     return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
795 }
796 
GetMacroName(sal_uInt16 nExtSheet,sal_uInt16 nExtName) const797 const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
798 {
799     return mxImpl->GetMacroName( nExtSheet, nExtName );
800 }
801 
802 // ============================================================================
803 
804