bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / filter / excel / xilink.cxx
bloba89d36625b5a25c90798101948652072085f7a25
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xilink.hxx"
21 #include "document.hxx"
22 #include "formulacell.hxx"
23 #include "scextopt.hxx"
24 #include "tablink.hxx"
25 #include "xistream.hxx"
26 #include "xihelper.hxx"
27 #include "xiname.hxx"
28 #include "excform.hxx"
29 #include "tokenarray.hxx"
30 #include "externalrefmgr.hxx"
32 #include <vector>
33 #include <boost/ptr_container/ptr_vector.hpp>
35 using ::std::vector;
38 // ============================================================================
39 // *** Helper classes ***
40 // ============================================================================
42 // Cached external cells ======================================================
44 /**
45 * Contains the address and value of an external referenced cell.
46 * Note that this is non-copyable, so cannot be used in most stl/boost containers.
48 class XclImpCrn : public XclImpCachedValue
50 public:
51 /** Reads a cached value and stores it with its cell address. */
52 explicit XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
54 const XclAddress& GetAddress() const;
56 private:
57 XclAddress maXclPos; /// Excel position of the cached cell.
60 // Sheet in an external document ==============================================
62 /** Contains the name and sheet index of one sheet in an external document. */
63 class XclImpSupbookTab
65 public:
66 /** Stores the sheet name and marks the sheet index as invalid.
67 The sheet index is set while creating the Calc sheet with CreateTable(). */
68 explicit XclImpSupbookTab( const String& rTabName );
69 ~XclImpSupbookTab();
71 inline const String& GetTabName() const { return maTabName; }
73 /** Reads a CRN record (external referenced cell) at the specified address. */
74 void ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
76 void LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable);
78 private:
79 typedef boost::shared_ptr< XclImpCrn > XclImpCrnRef;
80 typedef std::vector< XclImpCrnRef > XclImpCrnList;
82 XclImpCrnList maCrnList; /// List of CRN records (cached cell values).
83 String maTabName; /// Name of the external sheet.
86 // External document (SUPBOOK) ================================================
88 /** This class represents an external linked document (record SUPBOOK).
89 @descr Contains a list of all referenced sheets in the document. */
90 class XclImpSupbook : protected XclImpRoot
92 public:
93 /** Reads the SUPBOOK record from stream. */
94 explicit XclImpSupbook( XclImpStream& rStrm );
96 /** Reads an XCT record (count of following CRNs and current sheet). */
97 void ReadXct( XclImpStream& rStrm );
98 /** Reads a CRN record (external referenced cell). */
99 void ReadCrn( XclImpStream& rStrm );
100 /** Reads an EXTERNNAME record. */
101 void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
103 /** Returns the SUPBOOK record type. */
104 inline XclSupbookType GetType() const { return meType; }
106 /** Returns the URL of the external document. */
107 inline const String& GetXclUrl() const { return maXclUrl; }
109 /** Returns the external name specified by an index from the Excel document (one-based). */
110 const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
111 /** Tries to decode the URL to OLE or DDE link components.
112 @descr For DDE links: Decodes to application name and topic.
113 For OLE object links: Decodes to class name and document URL.
114 @return true = decoding was successful, returned strings are valid (not empty). */
115 bool GetLinkData( String& rApplic, String& rDoc ) const;
116 /** Returns the specified macro name (1-based) or an empty string on error. */
117 const String& GetMacroName( sal_uInt16 nXclNameIdx ) const;
119 const String& GetTabName( sal_uInt16 nXtiTab ) const;
121 sal_uInt16 GetTabCount() const;
123 void LoadCachedValues();
125 private:
126 typedef boost::ptr_vector< XclImpSupbookTab > XclImpSupbookTabList;
127 typedef boost::ptr_vector< XclImpExtName > XclImpExtNameList;
129 XclImpSupbookTabList maSupbTabList; /// All sheet names of the document.
130 XclImpExtNameList maExtNameList; /// All external names of the document.
131 String maXclUrl; /// URL of the external document (Excel mode).
132 String maFilterName; /// Detected filer name.
133 String maFilterOpt; /// Detected filer options.
134 XclSupbookType meType; /// Type of the supbook record.
135 sal_uInt16 mnSBTab; /// Current Excel sheet index from SUPBOOK for XCT/CRN records.
138 // Import link manager ========================================================
140 /** Contains the SUPBOOK index and sheet indexes of an external link.
141 @descr It is possible to enter a formula like =SUM(Sheet1:Sheet3!A1),
142 therefore here occurs a sheet range. */
143 struct XclImpXti
145 sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
146 sal_uInt16 mnSBTabFirst; /// Index to the first sheet of the range in the SUPBOOK.
147 sal_uInt16 mnSBTabLast; /// Index to the last sheet of the range in the SUPBOOK.
148 inline explicit XclImpXti() : mnSupbook( SAL_MAX_UINT16 ), mnSBTabFirst( SAL_MAX_UINT16 ), mnSBTabLast( SAL_MAX_UINT16 ) {}
151 inline XclImpStream& operator>>( XclImpStream& rStrm, XclImpXti& rXti )
153 return rStrm >> rXti.mnSupbook >> rXti.mnSBTabFirst >> rXti.mnSBTabLast;
156 // ----------------------------------------------------------------------------
158 /** Implementation of the link manager. */
159 class XclImpLinkManagerImpl : protected XclImpRoot
161 public:
162 explicit XclImpLinkManagerImpl( const XclImpRoot& rRoot );
164 /** Reads the EXTERNSHEET record. */
165 void ReadExternsheet( XclImpStream& rStrm );
166 /** Reads a SUPBOOK record. */
167 void ReadSupbook( XclImpStream& rStrm );
168 /** Reads an XCT record and appends it to the current SUPBOOK. */
169 void ReadXct( XclImpStream& rStrm );
170 /** Reads a CRN record and appends it to the current SUPBOOK. */
171 void ReadCrn( XclImpStream& rStrm );
172 /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
173 void ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
175 /** Returns true, if the specified XTI entry contains an internal reference. */
176 bool IsSelfRef( sal_uInt16 nXtiIndex ) const;
177 /** Returns the Calc sheet index range of the specified XTI entry.
178 @return true = XTI data found, returned sheet index range is valid. */
179 bool GetScTabRange(
180 SCTAB& rnFirstScTab, SCTAB& rnLastScTab,
181 sal_uInt16 nXtiIndex ) const;
182 /** Returns the specified external name or 0 on error. */
183 const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
185 /** Returns the absolute file URL of a supporting workbook specified by
186 the index. */
187 const String* GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
189 const String& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
191 /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
192 @descr For DDE links: Decodes to application name and topic.
193 For OLE object links: Decodes to class name and document URL.
194 @return true = decoding was successful, returned strings are valid (not empty). */
195 bool GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const;
196 /** Returns the specified macro name or an empty string on error. */
197 const String& GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
199 private:
200 /** Returns the specified XTI (link entry from BIFF8 EXTERNSHEET record). */
201 const XclImpXti* GetXti( sal_uInt16 nXtiIndex ) const;
202 /** Returns the specified SUPBOOK (external document). */
203 const XclImpSupbook* GetSupbook( sal_uInt16 nXtiIndex ) const;
205 void LoadCachedValues();
207 private:
208 typedef ::std::vector< XclImpXti > XclImpXtiVector;
209 typedef boost::ptr_vector< XclImpSupbook > XclImpSupbookList;
211 XclImpXtiVector maXtiList; /// List of all XTI structures.
212 XclImpSupbookList maSupbookList; /// List of external documents.
215 // ============================================================================
216 // *** Implementation ***
217 // ============================================================================
219 // Excel sheet indexes ========================================================
221 // original Excel sheet names -------------------------------------------------
223 void XclImpTabInfo::AppendXclTabName( const String& rXclTabName, SCTAB nScTab )
225 maTabNames[ rXclTabName ] = nScTab;
228 void XclImpTabInfo::InsertScTab( SCTAB nScTab )
230 for( XclTabNameMap::iterator aIt = maTabNames.begin(), aEnd = maTabNames.end(); aIt != aEnd; ++aIt )
231 if( aIt->second >= nScTab )
232 ++aIt->second;
235 SCTAB XclImpTabInfo::GetScTabFromXclName( const String& rXclTabName ) const
237 XclTabNameMap::const_iterator aIt = maTabNames.find( rXclTabName );
238 return (aIt != maTabNames.end()) ? aIt->second : SCTAB_INVALID;
241 // record creation order - TABID record ---------------------------------------
243 void XclImpTabInfo::ReadTabid( XclImpStream& rStrm )
245 OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() == EXC_BIFF8 );
246 if( rStrm.GetRoot().GetBiff() == EXC_BIFF8 )
248 rStrm.EnableDecryption();
249 sal_Size nReadCount = rStrm.GetRecLeft() / 2;
250 OSL_ENSURE( nReadCount <= 0xFFFF, "XclImpTabInfo::ReadTabid - record too long" );
251 maTabIdVec.clear();
252 maTabIdVec.reserve( nReadCount );
253 for( sal_Size nIndex = 0; rStrm.IsValid() && (nIndex < nReadCount); ++nIndex )
254 // zero index is not allowed in BIFF8, but it seems that it occurs in real life
255 maTabIdVec.push_back( rStrm.ReaduInt16() );
259 sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMaxTabId ) const
261 sal_uInt16 nReturn = 0;
262 for( ScfUInt16Vec::const_iterator aIt = maTabIdVec.begin(), aEnd = maTabIdVec.end(); aIt != aEnd; ++aIt )
264 sal_uInt16 nValue = *aIt;
265 if( nValue == nCreatedId )
266 return nReturn;
267 if( nValue <= nMaxTabId )
268 ++nReturn;
270 return 0;
273 // External names =============================================================
275 XclImpExtName::MOper::MOper(XclImpStream& rStrm) :
276 mxCached(new ScMatrix(0,0))
278 SCSIZE nLastCol = rStrm.ReaduInt8();
279 SCSIZE nLastRow = rStrm.ReaduInt16();
280 mxCached->Resize(nLastCol+1, nLastRow+1);
281 for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow)
283 for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol)
285 sal_uInt8 nOp;
286 rStrm >> nOp;
287 switch (nOp)
289 case 0x01:
291 double fVal = rStrm.ReadDouble();
292 mxCached->PutDouble(fVal, nCol, nRow);
294 break;
295 case 0x02:
297 OUString aStr = rStrm.ReadUniString();
298 mxCached->PutString(aStr, nCol, nRow);
300 break;
301 case 0x04:
303 bool bVal = rStrm.ReaduInt8();
304 mxCached->PutBoolean(bVal, nCol, nRow);
305 rStrm.Ignore(7);
307 break;
308 case 0x10:
310 sal_uInt8 nErr = rStrm.ReaduInt8();
311 // TODO: Map the error code from xls to calc.
312 mxCached->PutError(nErr, nCol, nRow);
313 rStrm.Ignore(7);
315 break;
316 default:
317 rStrm.Ignore(8);
323 const ScMatrix& XclImpExtName::MOper::GetCache() const
325 return *mxCached;
328 XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) :
329 mpMOper(NULL)
331 sal_uInt16 nFlags;
332 sal_uInt8 nLen;
334 rStrm >> nFlags >> mnStorageId >> nLen ;
335 maName = rStrm.ReadUniString( nLen );
336 if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
338 if( eSubType == EXC_SBTYPE_ADDIN )
340 meType = xlExtAddIn;
341 maName = rStrm.GetRoot().GetScAddInName( maName );
343 else if ( (eSubType == EXC_SBTYPE_EUROTOOL) &&
344 maName.EqualsIgnoreCaseAscii( "EUROCONVERT" ) )
345 meType = xlExtEuroConvert;
346 else
348 meType = xlExtName;
349 ScfTools::ConvertToScDefinedName( maName );
352 else
354 meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
357 switch (meType)
359 case xlExtDDE:
360 if (rStrm.GetRecLeft() > 1)
361 mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm));
362 break;
363 case xlExtName:
364 // TODO: For now, only global external names are supported. In future
365 // we should extend this to supporting per-sheet external names.
366 if (mnStorageId == 0)
368 if (pFormulaConv)
370 const ScTokenArray* pArray = NULL;
371 sal_uInt16 nFmlaLen;
372 rStrm >> nFmlaLen;
373 vector<String> aTabNames;
374 sal_uInt16 nCount = rSupbook.GetTabCount();
375 aTabNames.reserve(nCount);
376 for (sal_uInt16 i = 0; i < nCount; ++i)
377 aTabNames.push_back(rSupbook.GetTabName(i));
379 pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
380 if (pArray)
381 mxArray.reset(pArray->Clone());
384 break;
385 case xlExtOLE:
386 mpMOper = new MOper(rStrm);
387 break;
388 default:
393 XclImpExtName::~XclImpExtName()
395 delete mpMOper;
398 void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const
400 ScMatrixRef xResults;
401 if( mxDdeMatrix.get() )
402 xResults = mxDdeMatrix->CreateScMatrix();
403 rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
406 void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
408 if (!mxArray.get())
409 return;
411 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
412 pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
415 namespace {
418 * Decompose the name into sheet name and range name. An OLE link name is
419 * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
420 * notation.
422 bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange)
424 sal_Int32 n = rName.getLength();
425 const sal_Unicode* p = rName.getStr();
426 OUStringBuffer aBuf;
427 bool bInSheet = true;
428 for (sal_Int32 i = 0; i < n; ++i, ++p)
430 if (i == 0)
432 // first character must be '!'.
433 if (*p != '!')
434 return false;
435 continue;
438 if (*p == '!')
440 // sheet name to range separator.
441 if (!bInSheet)
442 return false;
443 rSheet = aBuf.makeStringAndClear();
444 bInSheet = false;
445 continue;
448 aBuf.append(*p);
451 rRange = aBuf.makeStringAndClear();
452 return true;
457 bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl,
458 sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const
460 if (!mpMOper)
461 return false;
463 OUString aSheet, aRangeStr;
464 if (!extractSheetAndRange(maName, aSheet, aRangeStr))
465 return false;
467 ScRange aRange;
468 sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
469 if ((nRes & SCA_VALID) != SCA_VALID)
470 return false;
472 if (aRange.aStart.Tab() != aRange.aEnd.Tab())
473 // We don't support multi-sheet range for this.
474 return false;
476 const ScMatrix& rCache = mpMOper->GetCache();
477 SCSIZE nC, nR;
478 rCache.GetDimensions(nC, nR);
479 if (!nC || !nR)
480 // cache matrix is empty.
481 return false;
483 ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
484 sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
485 ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL);
486 if (!xTab)
487 // cache table creation failed.
488 return false;
490 xTab->setWholeTableCached();
491 for (SCSIZE i = 0; i < nR; ++i)
493 for (SCSIZE j = 0; j < nC; ++j)
495 SCCOL nCol = aRange.aStart.Col() + j;
496 SCROW nRow = aRange.aStart.Row() + i;
498 ScMatrixValue aVal = rCache.Get(j, i);
499 switch (aVal.nType)
501 case SC_MATVAL_BOOLEAN:
503 bool b = aVal.GetBoolean();
504 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
505 xTab->setCell(nCol, nRow, pToken, 0, false);
507 break;
508 case SC_MATVAL_VALUE:
510 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal));
511 xTab->setCell(nCol, nRow, pToken, 0, false);
513 break;
514 case SC_MATVAL_STRING:
516 const String& rStr = aVal.GetString();
517 ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
518 xTab->setCell(nCol, nRow, pToken, 0, false);
520 break;
521 default:
527 rFileId = nFileId;
528 rTabName = aSheet;
529 rRange = aRange;
530 return true;
533 bool XclImpExtName::HasFormulaTokens() const
535 return (mxArray.get() != NULL);
538 // Cached external cells ======================================================
540 XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
541 XclImpCachedValue( rStrm ),
542 maXclPos( rXclPos )
546 const XclAddress& XclImpCrn::GetAddress() const
548 return maXclPos;
551 // Sheet in an external document ==============================================
553 XclImpSupbookTab::XclImpSupbookTab( const String& rTabName ) :
554 maTabName( rTabName )
558 XclImpSupbookTab::~XclImpSupbookTab()
562 void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
564 XclImpCrnRef crnRef( new XclImpCrn(rStrm, rXclPos) );
565 maCrnList.push_back( crnRef );
568 void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::TableTypeRef pCacheTable)
570 if (maCrnList.empty())
571 return;
573 for (XclImpCrnList::iterator itCrnRef = maCrnList.begin(); itCrnRef != maCrnList.end(); ++itCrnRef)
575 const XclImpCrn* const pCrn = itCrnRef->get();
576 const XclAddress& rAddr = pCrn->GetAddress();
577 switch (pCrn->GetType())
579 case EXC_CACHEDVAL_BOOL:
581 bool b = pCrn->GetBool();
582 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
583 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
585 break;
586 case EXC_CACHEDVAL_DOUBLE:
588 double f = pCrn->GetValue();
589 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(f));
590 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
592 break;
593 case EXC_CACHEDVAL_ERROR:
595 double fError = XclTools::ErrorToDouble( pCrn->GetXclError() );
596 ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(fError));
597 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
599 break;
600 case EXC_CACHEDVAL_STRING:
602 const String& rStr = pCrn->GetString();
603 ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
604 pCacheTable->setCell(rAddr.mnCol, rAddr.mnRow, pToken, 0, false);
606 break;
607 default:
613 // External document (SUPBOOK) ================================================
615 XclImpSupbook::XclImpSupbook( XclImpStream& rStrm ) :
616 XclImpRoot( rStrm.GetRoot() ),
617 meType( EXC_SBTYPE_UNKNOWN ),
618 mnSBTab( EXC_TAB_DELETED )
620 sal_uInt16 nSBTabCnt;
621 rStrm >> nSBTabCnt;
623 if( rStrm.GetRecLeft() == 2 )
625 switch( rStrm.ReaduInt16() )
627 case EXC_SUPB_SELF: meType = EXC_SBTYPE_SELF; break;
628 case EXC_SUPB_ADDIN: meType = EXC_SBTYPE_ADDIN; break;
629 default: OSL_FAIL( "XclImpSupbook::XclImpSupbook - unknown special SUPBOOK type" );
631 return;
634 String aEncUrl( rStrm.ReadUniString() );
635 bool bSelf = false;
636 XclImpUrlHelper::DecodeUrl( maXclUrl, bSelf, GetRoot(), aEncUrl );
638 if( maXclUrl.EqualsIgnoreCaseAscii( "\010EUROTOOL.XLA" ) )
640 meType = EXC_SBTYPE_EUROTOOL;
641 maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
643 else if( nSBTabCnt )
645 meType = EXC_SBTYPE_EXTERN;
646 for( sal_uInt16 nSBTab = 0; nSBTab < nSBTabCnt; ++nSBTab )
648 String aTabName( rStrm.ReadUniString() );
649 maSupbTabList.push_back( new XclImpSupbookTab( aTabName ) );
652 else
654 meType = EXC_SBTYPE_SPECIAL;
655 // create dummy list entry
656 maSupbTabList.push_back( new XclImpSupbookTab( maXclUrl ) );
660 void XclImpSupbook::ReadXct( XclImpStream& rStrm )
662 rStrm.Ignore( 2 );
663 rStrm >> mnSBTab;
666 void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
668 if (mnSBTab >= maSupbTabList.size())
669 return;
670 XclImpSupbookTab& rSbTab = maSupbTabList[mnSBTab];
671 sal_uInt8 nXclColLast, nXclColFirst;
672 sal_uInt16 nXclRow;
673 rStrm >> nXclColLast >> nXclColFirst >> nXclRow;
675 for( sal_uInt8 nXclCol = nXclColFirst; (nXclCol <= nXclColLast) && (rStrm.GetRecLeft() > 1); ++nXclCol )
676 rSbTab.ReadCrn( rStrm, XclAddress( nXclCol, nXclRow ) );
679 void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
681 maExtNameList.push_back( new XclImpExtName( *this, rStrm, meType, pFormulaConv ) );
684 const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
686 OSL_ENSURE( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" );
687 if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size())
688 return NULL;
689 return &maExtNameList[nXclIndex-1];
692 bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const
694 return (meType == EXC_SBTYPE_SPECIAL) && XclImpUrlHelper::DecodeLink( rApplic, rTopic, maXclUrl );
697 const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
699 OSL_ENSURE( nXclNameIdx > 0, "XclImpSupbook::GetMacroName - index must be >0" );
700 const XclImpName* pName = (meType == EXC_SBTYPE_SELF) ? GetNameManager().GetName( nXclNameIdx ) : 0;
701 return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
704 const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
706 if (nXtiTab >= maSupbTabList.size())
707 return EMPTY_STRING;
708 return maSupbTabList[nXtiTab].GetTabName();
711 sal_uInt16 XclImpSupbook::GetTabCount() const
713 return ulimit_cast<sal_uInt16>(maSupbTabList.size());
716 void XclImpSupbook::LoadCachedValues()
718 if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0 || !GetDocShell())
719 return;
721 String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
723 ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
724 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
726 for (XclImpSupbookTabList::iterator itTab = maSupbTabList.begin(); itTab != maSupbTabList.end(); ++itTab)
728 const String& rTabName = itTab->GetTabName();
729 ScExternalRefCache::TableTypeRef pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
730 itTab->LoadCachedValues(pCacheTable);
731 pCacheTable->setWholeTableCached();
735 // Import link manager ========================================================
737 XclImpLinkManagerImpl::XclImpLinkManagerImpl( const XclImpRoot& rRoot ) :
738 XclImpRoot( rRoot )
742 void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
744 sal_uInt16 nXtiCount;
745 rStrm >> nXtiCount;
746 OSL_ENSURE( static_cast< sal_Size >( nXtiCount * 6 ) == rStrm.GetRecLeft(), "XclImpLinkManagerImpl::ReadExternsheet - invalid count" );
747 nXtiCount = static_cast< sal_uInt16 >( ::std::min< sal_Size >( nXtiCount, rStrm.GetRecLeft() / 6 ) );
749 /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
750 records instead of only one as expected. Surprisingly, Excel seems to
751 insert the entries of the second record before the entries of the first
752 record. */
753 XclImpXtiVector aNewEntries( nXtiCount );
754 for( XclImpXtiVector::iterator aIt = aNewEntries.begin(), aEnd = aNewEntries.end(); rStrm.IsValid() && (aIt != aEnd); ++aIt )
755 rStrm >> *aIt;
756 maXtiList.insert( maXtiList.begin(), aNewEntries.begin(), aNewEntries.end() );
758 LoadCachedValues();
761 void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
763 maSupbookList.push_back( new XclImpSupbook( rStrm ) );
766 void XclImpLinkManagerImpl::ReadXct( XclImpStream& rStrm )
768 if( !maSupbookList.empty() )
769 maSupbookList.back().ReadXct( rStrm );
772 void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
774 if( !maSupbookList.empty() )
775 maSupbookList.back().ReadCrn( rStrm );
778 void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
780 if( !maSupbookList.empty() )
781 maSupbookList.back().ReadExternname( rStrm, pFormulaConv );
784 bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
786 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
787 return pSupbook && (pSupbook->GetType() == EXC_SBTYPE_SELF);
790 bool XclImpLinkManagerImpl::GetScTabRange(
791 SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
793 if( const XclImpXti* pXti = GetXti( nXtiIndex ) )
795 if (!maSupbookList.empty() && (pXti->mnSupbook < maSupbookList.size()) )
797 rnFirstScTab = pXti->mnSBTabFirst;
798 rnLastScTab = pXti->mnSBTabLast;
799 return true;
802 return false;
805 const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
807 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
808 return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
811 const String* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
813 const XclImpSupbook* p = GetSupbook( nXtiIndex );
814 if (!p)
815 return NULL;
816 return &p->GetXclUrl();
819 const String& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
821 const XclImpSupbook* p = GetSupbook(nXti);
822 return p ? p->GetTabName(nXtiTab) : EMPTY_STRING;
825 bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
827 const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
828 return pSupbook && pSupbook->GetLinkData( rApplic, rTopic );
831 const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
833 const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
834 return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
837 const XclImpXti* XclImpLinkManagerImpl::GetXti( sal_uInt16 nXtiIndex ) const
839 return (nXtiIndex < maXtiList.size()) ? &maXtiList[ nXtiIndex ] : 0;
842 const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt16 nXtiIndex ) const
844 if ( maSupbookList.empty() )
845 return NULL;
846 const XclImpXti* pXti = GetXti( nXtiIndex );
847 if (!pXti || pXti->mnSupbook >= maSupbookList.size())
848 return NULL;
849 return &(maSupbookList.at( pXti->mnSupbook ));
852 void XclImpLinkManagerImpl::LoadCachedValues()
854 // Read all CRN records which can be accessed via XclImpSupbook, and store
855 // the cached values to the external reference manager.
856 for (XclImpSupbookList::iterator itSupbook = maSupbookList.begin(); itSupbook != maSupbookList.end(); ++itSupbook)
857 itSupbook->LoadCachedValues();
860 // ============================================================================
862 XclImpLinkManager::XclImpLinkManager( const XclImpRoot& rRoot ) :
863 XclImpRoot( rRoot ),
864 mxImpl( new XclImpLinkManagerImpl( rRoot ) )
868 XclImpLinkManager::~XclImpLinkManager()
872 void XclImpLinkManager::ReadExternsheet( XclImpStream& rStrm )
874 mxImpl->ReadExternsheet( rStrm );
877 void XclImpLinkManager::ReadSupbook( XclImpStream& rStrm )
879 mxImpl->ReadSupbook( rStrm );
882 void XclImpLinkManager::ReadXct( XclImpStream& rStrm )
884 mxImpl->ReadXct( rStrm );
887 void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
889 mxImpl->ReadCrn( rStrm );
892 void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
894 mxImpl->ReadExternname( rStrm, pFormulaConv );
897 bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
899 return mxImpl->IsSelfRef( nXtiIndex );
902 bool XclImpLinkManager::GetScTabRange(
903 SCTAB& rnFirstScTab, SCTAB& rnLastScTab, sal_uInt16 nXtiIndex ) const
905 return mxImpl->GetScTabRange( rnFirstScTab, rnLastScTab, nXtiIndex );
908 const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const
910 return mxImpl->GetExternName( nXtiIndex, nExtName );
913 const String* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
915 return mxImpl->GetSupbookUrl(nXtiIndex);
918 const String& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
920 return mxImpl->GetSupbookTabName(nXti, nXtiTab);
923 bool XclImpLinkManager::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
925 return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
928 const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const
930 return mxImpl->GetMacroName( nExtSheet, nExtName );
933 // ============================================================================
935 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */