ooo-build r13457 - in trunk: . patches/test



Author: kyoshida
Date: Fri Aug  1 07:28:23 2008
New Revision: 13457
URL: http://svn.gnome.org/viewvc/ooo-build?rev=13457&view=rev

Log:
2008-08-01  Kohei Yoshida  <kyoshida novell com>

	* patches/test/calc-external-defined-names.diff: more progress; make 
	full use of cached external data to speed up file loading, fixed once
	again the xls import/export filters to correctly read/write external
	data, and more.


Modified:
   trunk/ChangeLog
   trunk/patches/test/calc-external-defined-names.diff

Modified: trunk/patches/test/calc-external-defined-names.diff
==============================================================================
--- trunk/patches/test/calc-external-defined-names.diff	(original)
+++ trunk/patches/test/calc-external-defined-names.diff	Fri Aug  1 07:28:23 2008
@@ -203,10 +203,10 @@
          @return  TRUE = Sheet created, rnTab contains valid sheet index. */
 diff --git sc/inc/externalrefmgr.hxx sc/inc/externalrefmgr.hxx
 new file mode 100644
-index 0000000..1245062
+index 0000000..08b0c53
 --- /dev/null
 +++ sc/inc/externalrefmgr.hxx
-@@ -0,0 +1,288 @@
+@@ -0,0 +1,343 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -246,6 +246,7 @@
 +#include "sfx2/lnkbase.hxx"
 +#include "tools/time.hxx"
 +#include "vcl/timer.hxx"
++#include "scmatrix.hxx"
 +
 +#include <hash_map>
 +#include <hash_set>
@@ -293,36 +294,126 @@
 + */
 +class ScExternalRefCache
 +{
++    struct RangeHash
++    {
++        size_t operator()(const ScRange& rRange) const
++        {
++            const ScAddress& s = rRange.aStart;
++            const ScAddress& e = rRange.aEnd;
++            return s.Tab() + s.Col() + s.Row() + e.Tab() + e.Col() + e.Row();
++        }
++    };
++
 +public:
-+    typedef ::boost::shared_ptr<ScToken> TokenRef;
-+    typedef ::boost::shared_ptr<ScMatrix> MatrixRef;
++    
++    typedef ::boost::shared_ptr<ScToken>            TokenRef;
++    typedef ::boost::shared_ptr<ScTokenArray>       TokenArrayRef;
++    typedef ::std::hash_map<SCCOL, TokenRef>        RowDataType;
++    typedef ::std::hash_map<SCROW, RowDataType>     RowsDataType;
++
++    class Table
++    {
++    public:
++        Table();
++        ~Table();
++
++        void setCell(SCROW nRow, SCCOL nCol, TokenRef pToken);
++        ScToken* getCell(SCROW nRow, SCCOL nCol) const;
++
++    private:
++        RowsDataType maRows;
++    };
++
++    typedef ::boost::shared_ptr<Table>      TableTypeRef;
++    typedef ::std::hash_map<String, size_t, ScStringHashCode>   TableNameIndexMap;
 +
 +    ScExternalRefCache();
 +    ~ScExternalRefCache();
 +
++    /** 
++     * Get a cached cell data at specified cell location.
++     *
++     * @param nFileId file ID of an external document
++     * @param rTabName sheet name
++     * @param nRow 
++     * @param nCol 
++     * 
++     * @return pointer to the token instance in the cache.  <i>The caller does
++     *         not need to delete this instance since its life cycle is
++     *         managed by this class.</i>
++     */
 +    ScToken* getCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol);
++
++    /** 
++     * Get a cached cell range data. 
++     *  
++     * @return a new token array instance.  Note that <i>the caller must 
++     *         manage the life cycle of the returned instance</i>.
++     */
 +    ScTokenArray* getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange);
 +
++    ScTokenArray* getRangeNameTokens(sal_uInt16 nFileId, const String& rName);
++    void setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray);
++
 +    void setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken);
-+    void setCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange,
-+                          const ::std::vector<MatrixRef>& rData);
++
++    struct SingleRangeData
++    {
++        String      maTableName;
++        ScMatrixRef mpRangeData;
++    };
++    void setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const ::std::vector<SingleRangeData>& rData,
++                          TokenArrayRef pArray);
++
++    bool isDocInitialized(sal_uInt16 nFileId);
++    void initializeDoc(sal_uInt16 nFileId, const ::std::vector<String>& rTabNames);
++#if 0
++    const String* getExternalTableName(sal_uInt16 nFileId, SCTAB nTab);
++    SCTAB getExternalTableId(sal_uInt16 nFileId, const String& rTabName);
++#endif
++    const ::std::vector<String>* getAllTableNames(sal_uInt16 nFileId) const;
++
++    /** 
++     * Get a cache table instance for specified file and table name.  If the 
++     * table instance is not already present, it'll instantiate a new one and 
++     * append it to the end of the table array.  <I>It's important to be 
++     * aware of this fact especially for multi-table ranges for which 
++     * table orders are critical.</I> 
++     *  
++     * Excel filter calls this method to populate the cache table from the 
++     * XCT/CRN records. 
++     *
++     * @param nFileId file ID
++     * @param rTabName table name
++     * 
++     * @return pointer to the cache table instance
++     */
++    Table* getCacheTable(sal_uInt16 nFileId, const String& rTabName);
++
++    void clearCache(sal_uInt16 nFileId);
 +
 +private:
-+    typedef ::std::hash_map<SCCOL, TokenRef>        RowDataType;
-+    typedef ::std::hash_map<SCROW, RowDataType>     TableDataType;
-+    typedef ::boost::shared_ptr<TableDataType>      TableDataTypeRef;
-+    typedef ::std::vector<TableDataTypeRef>         TableListType;
++    typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode>    RangeNameMap;
++    typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash>          RangeArrayMap;
 +
-+    typedef ::std::hash_map<String, size_t, ScStringHashCode>   TableNameIndexMap;
-+    
++    /** Represents data cached for a single external document. */
 +    struct DocItem
 +    {
-+        TableListType       maTables;
-+        TableNameIndexMap   maTableNameIndex;    
++        ::std::vector<TableTypeRef> maTables;
++        ::std::vector<String>       maTableNames; 
++        TableNameIndexMap           maTableNameIndex;
++        RangeNameMap                maRangeNames;
++        RangeArrayMap               maRangeArrays;
++
++        bool mbInitFromSource;
++
++        DocItem() : mbInitFromSource(false) {}
 +    };
 +    typedef ::std::hash_map<sal_uInt16, DocItem>  DocDataType;
++    DocItem* getDocItem(sal_uInt16 nFileId) const;
 +
-+    DocDataType maDocs;
++private:
++    mutable DocDataType maDocs;
 +};
 +
 +// ============================================================================
@@ -339,16 +430,6 @@
 +        }
 +    };
 +
-+    struct RangeHash
-+    {
-+        size_t operator()(const ScRange& rRange) const
-+        {
-+            const ScAddress& s = rRange.aStart;
-+            const ScAddress& e = rRange.aEnd;
-+            return s.Tab() + s.Col() + s.Row() + e.Tab() + e.Col() + e.Row();
-+        }
-+    };
-+
 +    struct SrcDoc
 +    {
 +        SfxObjectShellRef   maShell;
@@ -359,40 +440,34 @@
 +    typedef ::boost::shared_ptr<ScTokenArray>   TokenArrayRef;
 +
 +    typedef ::std::hash_map<sal_uInt16, SrcDoc>                                                 DocShellMap;
-+    typedef ::std::hash_map<ScAddress, TokenRef, AddressHash, ::std::equal_to<ScAddress> >      SingleTokenMap;
-+    typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash, ::std::equal_to<ScRange> >       DoubleTokenMap;
-+    typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode, ::std::equal_to<String> >  RangeNameMap;
 +    typedef ::std::hash_set<sal_uInt16, ScStringHashCode>                                       LinkedDocSet;
 +
 +    typedef ::std::hash_set<ScAddress, AddressHash, ::std::equal_to<ScAddress> >    RefCellSet;
 +    typedef ::std::hash_map<sal_uInt16, RefCellSet>                                 RefCellMap;
 +
-+    /** 
-+     * Cached content of a single external document
-+     */
-+    struct DocCache
-+    {
-+        SingleTokenMap  maSingleTokens;
-+        DoubleTokenMap  maDoubleTokens;
-+        RangeNameMap    maRangeNames;
-+        ::std::vector<String> maTableNames;
-+    };
-+    typedef ::boost::shared_ptr<DocCache> DocCacheRef;
-+    typedef ::std::hash_map<sal_uInt16, DocCacheRef>   DocCacheMap;
-+
 +public:
 +    explicit ScExternalRefManager(ScDocument* pDoc);
 +    ~ScExternalRefManager();
 +
++    ScExternalRefCache::Table* getCacheTable(sal_uInt16 nFileId, const String& rTabName);
++    void storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray);
++
 +    ScToken* getSingleRefToken(sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell, const ScAddress* pCurPos, SCTAB* pTab);
-+#if 1
-+    ScToken* getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress* pCurPos);
-+#endif
 +
++    /** 
++     * Get an array of tokens that consist of the specified external cell 
++     * range. 
++     *
++     * @param nFileId file ID for an external document
++     * @param rTabName referenced sheet name
++     * @param rRange referenced cell range
++     * @param pCurPos current cursor position to keep track of cells that 
++     *                reference an external data.
++     * 
++     * @return pointer to a token array instance.  <i>The caller must not 
++     *         delete the instance returned by this method.</i>
++     */
 +    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos);
-+#if 1
-+    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress* pCurPos);
-+#endif
 +
 +    /** 
 +     * Get an array of tokens corresponding with a specified name in a 
@@ -416,18 +491,7 @@
 +    void convertToAbsName(String& rFile) const;
 +    sal_uInt16 getExternalFileId(const String& rFile);
 +    const String* getExternalFileName(sal_uInt16 nFileId) const;
-+    const String* getExternalTableName(sal_uInt16 nFileId, SCTAB nTabId);
-+
-+    /** 
-+     * Get the table index of an external table from its name.
-+     *
-+     * @param nFileId external file ID
-+     * @param rTabName table name
-+     * 
-+     * @return table index, or -1 if the name is not found.
-+     */
-+    SCTAB getExternalTableId(sal_uInt16 nFileId, const String& rTabName);
-+    
++    const ::std::vector<String>* getAllCachedTableNames(sal_uInt16 nFileId) const;
 +    void refreshNames(sal_uInt16 nFileId);
 +    void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile);
 +    void removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink);
@@ -437,17 +501,10 @@
 +    ScExternalRefManager();
 +    ScExternalRefManager(const ScExternalRefManager&); 
 +
-+#if 1
-+    ScToken* getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell);
-+#endif
-+
-+    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange);
-+
 +    void refreshAllReferencingCells(sal_uInt16 nFileId);
 +
 +    void insertReferencingCell(sal_uInt16 nFileId, const ScAddress& rCell);
 +
-+    DocCache* getDocumentCache(sal_uInt16 nFileId);
 +    ScDocument* getSrcDocument(sal_uInt16 nFileId);
 +    SfxObjectShellRef loadSrcDocument(const String& rFile, String& rFilter);
 +    void insertExternalFileLink(sal_uInt16 nFileId, const String& rFilterName);
@@ -463,6 +520,7 @@
 +    void purgeStaleSrcDocument(sal_Int32 nTimeOut);
 +
 +private:
++    /** cache only of referenced ranges and names from source documents. */
 +    ScExternalRefCache maRefCache;
 +
 +    ScDocument* mpDoc;
@@ -474,15 +532,12 @@
 +     */
 +    DocShellMap maDocShells;
 +
-+    /** cache only of referenced ranges and names from source documents. */
-+    DocCacheMap maCachedDocContents;
-+
 +    /** list of source documents that are managed by the link manager. */
 +    LinkedDocSet maLinkedDocs;
 +
 +    /** 
-+     *  List of referencing cells that may contain external names.  There is
-+     *  one list per source document.
++     * List of referencing cells that may contain external names.  There is
++     * one list per source document.
 +     */
 +    RefCellMap maRefCells;
 +
@@ -508,7 +563,7 @@
  		ocIf				= SC_OPCODE_IF,
  		ocChose				= SC_OPCODE_CHOSE,
 diff --git sc/inc/token.hxx sc/inc/token.hxx
-index ded3a94..92a9137 100644
+index ded3a94..7e49031 100644
 --- sc/inc/token.hxx
 +++ sc/inc/token.hxx
 @@ -64,7 +64,7 @@ enum StackVarEnum
@@ -520,7 +575,7 @@
      svError,                            // error token
      svMissing = 0x70,                   // 0 or ""
      svSep,                              // separator, ocSep, ocOpen, ocClose
-@@ -448,6 +448,65 @@ public:
+@@ -448,6 +448,69 @@ public:
  };
  
  
@@ -560,6 +615,10 @@
 +
 +    virtual USHORT                 GetIndex() const;
 +    virtual const String&          GetString() const;
++    virtual const SingleRefData&   GetSingleRef() const;
++    virtual SingleRefData&         GetSingleRef();
++    virtual const SingleRefData&   GetSingleRef2() const;
++    virtual SingleRefData&         GetSingleRef2();
 +    virtual const ComplRefData&    GetDoubleRef() const;
 +    virtual ComplRefData&          GetDoubleRef();
 +    virtual BOOL                    operator==( const ScToken& rToken ) const;
@@ -937,7 +996,7 @@
      case ScAddress::CONV_XL_A1:
          return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, FALSE );
 diff --git sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx
-index f88d5d3..563adf9 100644
+index 084f533..820192e 100644
 --- sc/source/core/tool/compiler.cxx
 +++ sc/source/core/tool/compiler.cxx
 @@ -74,9 +74,38 @@
@@ -979,7 +1038,7 @@
  
  #if OSL_DEBUG_LEVEL > 1
  // For some unknown reason the identical dbg_dump utilities in
-@@ -1165,6 +1194,174 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P
+@@ -1175,6 +1204,174 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P
      return true;
  }
  
@@ -1154,7 +1213,7 @@
  struct Convention_A1 : public ScCompiler::Convention
  {
      Convention_A1( ScAddress::Convention eConv ) : ScCompiler::Convention( eConv ) { }
-@@ -1185,7 +1382,7 @@ struct Convention_A1 : public ScCompiler::Convention
+@@ -1195,7 +1392,7 @@ struct Convention_A1 : public ScCompiler::Convention
              KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
          static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
          // '?' allowed in range names because of Xcl :-/
@@ -1163,7 +1222,7 @@
          return pCharClass->parseAnyToken( rFormula,
                  nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
      }
-@@ -1368,6 +1565,81 @@ struct ConventionOOO_A1 : public Convention_A1
+@@ -1378,6 +1575,81 @@ struct ConventionOOO_A1 : public Convention_A1
  
          return sal_Unicode(0);
      }
@@ -1245,7 +1304,7 @@
  };
  
  
-@@ -1489,6 +1761,16 @@ struct ConventionXL
+@@ -1499,6 +1771,16 @@ struct ConventionXL
          }
          return sal_Unicode(0);
      }
@@ -1262,7 +1321,7 @@
  };
  
  struct ConventionXL_A1 : public Convention_A1, public ConventionXL
-@@ -1587,6 +1869,16 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+@@ -1597,6 +1879,16 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
      {
          return ConventionXL::getSpecialSymbol(eSymType);
      }
@@ -1279,7 +1338,7 @@
  };
  
  static const ConventionXL_A1 ConvXL_A1;
-@@ -1714,6 +2006,16 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
+@@ -1724,6 +2016,16 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
      {
          return ConventionXL::getSpecialSymbol(eSymType);
      }
@@ -1296,7 +1355,7 @@
  };
  
  static const ConventionXL_R1C1 ConvXL_R1C1;
-@@ -1888,6 +2190,7 @@ sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub
+@@ -1898,6 +2200,7 @@ sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub
  
  xub_StrLen ScCompiler::NextSymbol(bool bInArray)
  {
@@ -1304,7 +1363,7 @@
      cSymbol[MAXSTRLEN-1] = 0;       // Stopper
      sal_Unicode* pSym = cSymbol;
      const sal_Unicode* const pStart = aFormula.GetBuffer();
-@@ -1912,6 +2215,11 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -1922,6 +2225,11 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
      bool bAutoIntersection = false;
      int nRefInSheetName = 0;
      mnPredetectedReference = 0;
@@ -1316,7 +1375,7 @@
      // try to parse simple tokens before calling i18n parser
      while ((c != 0) && (eState != ssStop) )
      {
-@@ -2169,7 +2477,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2179,7 +2487,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
                      static const int kQuote = kInc * 2;
                      static const int kPast = kInc * 3;
                      bool bAddToSymbol = true;
@@ -1325,7 +1384,7 @@
                      {
                          // eat it, no sheet name
                          bAddToSymbol = false;
-@@ -2184,7 +2492,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2194,7 +2502,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
                      }
                      else if (nRefInSheetName < kPast)
                      {
@@ -1334,7 +1393,7 @@
                              nRefInSheetName += kDollar;
                          else if ('\'' == c)
                          {
-@@ -2235,6 +2543,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2245,6 +2553,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
          cLast = c;
          c = *pSrc;
      }
@@ -1342,7 +1401,7 @@
      if ( bi18n )
      {
          nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces );
-@@ -2287,6 +2596,9 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2297,6 +2606,9 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
          aCorrectedSymbol = cSymbol;
      if (bAutoIntersection && nSpaces > 1)
          --nSpaces;  // replace '!!' with only one space
@@ -1352,7 +1411,7 @@
      return nSpaces;
  }
  
-@@ -2506,7 +2818,8 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
+@@ -2516,7 +2828,8 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
  {
      ScRange aRange( aPos, aPos );
      const ScAddress::Details aDetails( pConv->meConv, aPos );
@@ -1362,7 +1421,7 @@
      if( nFlags & SCA_VALID )
      {
          ScRawToken aToken;
-@@ -2525,23 +2838,41 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
+@@ -2535,23 +2848,41 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
              aRef.Ref2.SetTabDeleted( TRUE );        // #REF!
          aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
          aRef.CalcRelFromAbs( aPos );
@@ -1406,7 +1465,7 @@
          ScRawToken aToken;
          SingleRefData aRef;
          aRef.InitAddress( aAddr );
-@@ -2561,16 +2892,28 @@ BOOL ScCompiler::IsSingleReference( const String& rName )
+@@ -2571,16 +2902,28 @@ BOOL ScCompiler::IsSingleReference( const String& rName )
              nFlags |= SCA_VALID;
          }
          aRef.CalcRelFromAbs( aPos );
@@ -1436,7 +1495,7 @@
      // Has to be called before IsValue
      sal_Unicode ch1 = rName.GetChar(0);
      sal_Unicode cDecSep = ( mxSymbols->isEnglish() ? '.' :
-@@ -2669,6 +3012,30 @@ BOOL ScCompiler::IsNamedRange( const String& rUpperName )
+@@ -2679,6 +3022,30 @@ BOOL ScCompiler::IsNamedRange( const String& rUpperName )
          return FALSE;
  }
  
@@ -1467,7 +1526,7 @@
  BOOL ScCompiler::IsDBRange( const String& rName )
  {
      USHORT n;
-@@ -3267,6 +3634,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
+@@ -3277,6 +3644,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
                && !(bAllowBooleans && IsBoolean( aUpper ))
                && !IsValue( aUpper )
                && !IsNamedRange( aUpper )
@@ -1475,7 +1534,7 @@
                && !IsDBRange( aUpper )
                && !IsColRowName( aUpper )
                && !(bMayBeFuncName && IsMacro( aUpper ))
-@@ -3593,6 +3961,69 @@ BOOL ScCompiler::GetToken()
+@@ -3603,6 +3971,70 @@ BOOL ScCompiler::GetToken()
      }
      if( pToken->GetOpCode() == ocSubTotal )
          glSubTotal = TRUE;
@@ -1534,6 +1593,7 @@
 +                ScTokenArray* pNew = pRefMgr->getDoubleRefTokens(pToken->GetIndex(), pToken->GetString(), aRange, &aPos);
 +                if (pNew)
 +                {
++                    // This is already a new instance - no need to clone it.
 +                    PushTokenArray(pNew->Clone(), true);
 +                    return GetToken();
 +                }
@@ -1545,7 +1605,7 @@
      else if( pToken->GetOpCode() == ocName )
      {
          ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
-@@ -5543,6 +5974,7 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
+@@ -5553,6 +5985,7 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
      BOOL bSpaces = FALSE;
      ScToken* t = pTokenP;
      OpCode eOp = t->GetOpCode();
@@ -1553,7 +1613,7 @@
      if( eOp >= ocAnd && eOp <= ocOr )
      {
          // AND, OR infix?
-@@ -5590,111 +6022,141 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
+@@ -5600,111 +6033,141 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
          DBG_ERRORFILE("unknown OpCode");
          rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
      }
@@ -1782,7 +1842,7 @@
          rBuffer.append(sal_Unicode(' '));
      if ( bAllowArrAdvance )
 diff --git sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx
-index a20cbd5..25090a8 100644
+index a20cbd5..438f46a 100644
 --- sc/source/core/tool/token.cxx
 +++ sc/source/core/tool/token.cxx
 @@ -54,6 +54,33 @@
@@ -2034,7 +2094,7 @@
          }
          if (!xRes)
              return NULL;    // shouldn't happen..
-@@ -1035,6 +1149,170 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
+@@ -1035,6 +1149,190 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
      return ScToken::operator==( r ) && nIndex == r.GetIndex();
  }
  
@@ -2126,6 +2186,26 @@
 +    return maTabName;
 +}
 +
++const SingleRefData& ScExternalDoubleRefToken::GetSingleRef() const
++{
++    return maDoubleRef.Ref1;
++}
++
++SingleRefData& ScExternalDoubleRefToken::GetSingleRef()
++{
++    return maDoubleRef.Ref1;
++}
++
++const SingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const
++{
++    return maDoubleRef.Ref2;
++}
++
++SingleRefData& ScExternalDoubleRefToken::GetSingleRef2()
++{
++    return maDoubleRef.Ref2;
++}
++
 +const ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() const
 +{
 +    return maDoubleRef;
@@ -2205,7 +2285,7 @@
  
  short* ScJumpToken::GetJump() const                     { return pJump; }
  BOOL ScJumpToken::operator==( const ScToken& r ) const
-@@ -1893,6 +2171,21 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
+@@ -1893,6 +2191,21 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
      return Add( new ScMatrixToken( p ) );
  }
  
@@ -2227,16 +2307,45 @@
  ScToken* ScTokenArray::AddColRowName( const SingleRefData& rRef )
  {
      return Add( new ScSingleRefOpToken( ocColRowName, rRef ) );
+diff --git sc/source/filter/excel/excform.cxx sc/source/filter/excel/excform.cxx
+index 3070f34..fd87dbf 100644
+--- sc/source/filter/excel/excform.cxx
++++ sc/source/filter/excel/excform.cxx
+@@ -46,6 +46,7 @@
+ #include "xilink.hxx"
+ #include "xiname.hxx"
+ 
++using ::std::vector;
+ 
+ const UINT16 ExcelToSc::nRowMask = 0x3FFF;
+ const UINT16 ExcelToSc::nLastInd = 399;
+@@ -1329,6 +1330,13 @@ ConvErr ExcelToSc::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal
+ 	return eRet;
+ }
+ 
++ConvErr ExcelToSc::ConvertExternName( const ScTokenArray*& /*rpArray*/, XclImpStream& /*rStrm*/, sal_Size /*nFormulaLen*/,
++                                      const String& /*rUrl*/, const vector<String>& /*rTabNames*/ )
++{
++    // not implemented ...
++    return ConvErrNi;
++}
++
+ BOOL ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen )
+ {
+     DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF5 );
 diff --git sc/source/filter/excel/excform8.cxx sc/source/filter/excel/excform8.cxx
-index ebf8543..e4968c2 100644
+index ebf8543..be5ec15 100644
 --- sc/source/filter/excel/excform8.cxx
 +++ sc/source/filter/excel/excform8.cxx
-@@ -41,6 +41,32 @@
+@@ -41,6 +41,35 @@
  #include "xilink.hxx"
  #include "xiname.hxx"
  
 +#include "externalrefmgr.hxx"
 +
++#include <vector>
++
++using ::std::vector;
 +
 +namespace {
 +
@@ -2264,7 +2373,7 @@
  
  ExcelToSc8::ExcelToSc8( const XclImpRoot& rRoot ) :
      ExcelToSc( rRoot ),
-@@ -53,15 +79,23 @@ ExcelToSc8::~ExcelToSc8()
+@@ -53,15 +82,23 @@ ExcelToSc8::~ExcelToSc8()
  {
  }
  
@@ -2276,17 +2385,17 @@
 +    const String* pFileUrl = rLinkMan.GetSupbookUrl(nIxti);
 +    if (!pFileUrl || pFileUrl->Len() == 0)
 +        return false;
- 
--	UINT16 nIxti;
--    rStrm >> nIxti;
++
 +    String aFileUrl = ScGlobal::GetAbsDocName(*pFileUrl, GetDocShell());
 +    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
 +    rFileId = pRefMgr->getExternalFileId(aFileUrl);
  
--    return rLinkMan.GetScTabRange( rFirstTab, rLastTab, nIxti );
+-	UINT16 nIxti;
+-    rStrm >> nIxti;
 +    return true;
 +}
-+
+ 
+-    return rLinkMan.GetScTabRange( rFirstTab, rLastTab, nIxti );
 +bool ExcelToSc8::Read3DTabReference( SCTAB& rFirstTab, SCTAB& rLastTab, UINT16 nIxti )
 +{
 +	rFirstTab = rLastTab = 0;
@@ -2294,7 +2403,7 @@
  }
  
  
-@@ -608,8 +642,14 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+@@ -608,8 +645,15 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
                      {
                          case xlExtName:
                          {
@@ -2308,10 +2417,11 @@
 +                            }
 +
 +                            aStack << aPool.StoreExtName(nFileId, pExtName->GetName());
++                            pExtName->CreateExtNameData(GetDoc(), nFileId);
                          }
                          break;
  
-@@ -657,47 +697,81 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+@@ -657,47 +701,81 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
  			case 0x7C:
  			case 0x3C: // Deleted 3-D Cell Reference			[    277]
  			{
@@ -2427,7 +2537,7 @@
  			}
  				break;
  			case 0x5B:
-@@ -707,55 +781,75 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+@@ -707,55 +785,75 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
  			case 0x7D:
  			case 0x3D: // Deleted 3-D Area Reference			[    277]
  			{
@@ -2544,6 +2654,190 @@
  			}
  				break;
  			default: bError = TRUE;
+@@ -1143,7 +1241,135 @@ ConvErr ExcelToSc8::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sa
+ 	return eRet;
+ }
+ 
++ConvErr ExcelToSc8::ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                       const String& rUrl, const vector<String>& rTabNames )
++{
++    StackPrinter __stack_print__("ExcelToSc8::ConvertExternName");
++    String aFileUrl = ScGlobal::GetAbsDocName(rUrl, GetDocShell());
++
++    sal_uInt8               nOp, nByte;
++    bool                    bError = false;
++
++    SingleRefData           aSRD;
++    ComplRefData            aCRD;
++
++    if (eStatus != ConvOK)
++    {
++        rStrm.Ignore(nFormulaLen);
++        return eStatus;
++    }
++
++    if (nFormulaLen == 0)
++    {
++        aPool.Store(CREATE_STRING("-/-"));
++        aPool >> aStack;
++        rpArray = aPool[aStack.Get()];
++        return ConvOK;
++    }
+ 
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFileUrl);
++    sal_uInt16 nTabCount = rTabNames.size();
++
++    sal_Size nEndPos = rStrm.GetRecPos() + nFormulaLen;
++
++    while( (rStrm.GetRecPos() < nEndPos) && !bError )
++    {
++        rStrm >> nOp;
++
++        // #98524# always reset flags
++        aSRD.InitFlags();
++        aCRD.InitFlags();
++
++        switch( nOp )
++        {
++            case 0x1C: // Error Value
++            {
++                rStrm >> nByte;
++                DefTokenId eOc;
++                switch( nByte )
++                {
++                    case EXC_ERR_NULL:
++                    case EXC_ERR_DIV0:
++                    case EXC_ERR_VALUE:
++                    case EXC_ERR_REF:
++                    case EXC_ERR_NAME:
++                    case EXC_ERR_NUM:   eOc = ocStop;       break;
++                    case EXC_ERR_NA:    eOc = ocNotAvail;   break;
++                    default:            eOc = ocNoName;
++                }
++                aPool << eOc;
++                if( eOc != ocStop )
++                    aPool << ocOpen << ocClose;
++                aPool >> aStack;
++            }
++            break;
++            case 0x3A:
++            {
++                // cell reference in external range name
++                fprintf(stdout, "ExcelToSc8::ConvertExternName:   cell reference (0x3A)\n");
++                sal_uInt16 nExtTab1, nExtTab2, nRow, nGrbitCol;
++                rStrm >> nExtTab1 >> nExtTab2 >> nRow >> nGrbitCol;
++                fprintf(stdout, "ExcelToSc8::ConvertExternName:   tab1 = %d; tab2 = %d\n", nExtTab1, nExtTab2);
++                if (nExtTab1 >= nTabCount || nExtTab2 >= nTabCount)
++                {
++                    bError = true;
++                    break;
++                }
++
++                aSRD.nTab = nExtTab1;
++                aSRD.SetFlag3D(true);
++                aSRD.SetTabRel(false);
++                ExcRelToScRel8(nRow, nGrbitCol, aSRD, true);
++                aCRD.Ref1 = aCRD.Ref2 = aSRD;
++                String aTabName = rTabNames[nExtTab1];
++
++                if (nExtTab1 == nExtTab2)
++                {
++                    // single cell reference
++                    aStack << aPool.StoreExtRef(nFileId, aTabName, aSRD);
++                }
++                else
++                {    
++                    // area reference
++                    aCRD.Ref2.nTab = nExtTab2;
++                    aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD);
++                }
++                fprintf(stdout, "ExcelToSc8::ConvertExternName:   external ref inserted\n");
++            }
++            break;
++            default: 
++                fprintf(stdout, "ExcelToSc8::ConvertExternName:   un-handled opcode (%2.2X)\n", nOp);
++                bError = true;
++        }
++        bError |= !rStrm.IsValid();
++    }
++
++    ConvErr eRet;
++
++    if( bError )
++    {
++        aPool << ocBad;
++        aPool >> aStack;
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvErrNi;
++    }
++    else if( rStrm.GetRecPos() != nEndPos )
++    {
++        aPool << ocBad;
++        aPool >> aStack;
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvErrCount;
++    }
++    else
++    {
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvOK;
++    }
++
++    rStrm.Seek(nEndPos);
++    return eRet;
++}
+ 
+ void ExcelToSc8::ExcRelToScRel8( UINT16 nRow, UINT16 nC, SingleRefData &rSRD, const BOOL bName )
+ {
+diff --git sc/source/filter/excel/impop.cxx sc/source/filter/excel/impop.cxx
+index 258a7c7..4687365 100644
+--- sc/source/filter/excel/impop.cxx
++++ sc/source/filter/excel/impop.cxx
+@@ -98,6 +98,30 @@
+ using namespace ::com::sun::star;
+ 
+ 
++namespace {
++
++#include <string>
++
++class StackPrinter
++{
++public:
++    explicit StackPrinter(const char* msg) :
++        msMsg(msg)
++    {
++        fprintf(stdout, "%s: --begin\n", msMsg.c_str());
++    }
++
++    ~StackPrinter()
++    {
++        fprintf(stdout, "%s: --end\n", msMsg.c_str());
++    }
++
++private:
++    ::std::string msMsg;
++};
++
++}
++
+ const double ImportExcel::fExcToTwips =
+ 	( double ) TWIPS_PER_CHAR / 256.0;
+ 
+diff --git sc/source/filter/excel/read.cxx sc/source/filter/excel/read.cxx
+index 2cc592c..7f1c44b 100644
+--- sc/source/filter/excel/read.cxx
++++ sc/source/filter/excel/read.cxx
+@@ -967,7 +967,7 @@ FltError ImportExcel8::Read( void )
+                     case EXC_ID_SUPBOOK:        rLinkMgr.ReadSupbook( maStrm );     break;
+                     case EXC_ID_XCT:            rLinkMgr.ReadXct( maStrm );         break;
+                     case EXC_ID_CRN:            rLinkMgr.ReadCrn( maStrm );         break;
+-                    case EXC_ID_EXTERNNAME:     rLinkMgr.ReadExternname( maStrm );  break;
++                    case EXC_ID_EXTERNNAME:     rLinkMgr.ReadExternname( maStrm, pFormConv );  break;
+ 
+                     case EXC_ID_MSODRAWINGGROUP:rObjMgr.ReadMsoDrawingGroup( maStrm ); break;
+ 
 diff --git sc/source/filter/excel/tokstack.cxx sc/source/filter/excel/tokstack.cxx
 index 20ada63..9c4ddba 100644
 --- sc/source/filter/excel/tokstack.cxx
@@ -2688,7 +2982,7 @@
  
  
 diff --git sc/source/filter/excel/xeformula.cxx sc/source/filter/excel/xeformula.cxx
-index 3db8da7..65a5775 100644
+index 3db8da7..0debb70 100644
 --- sc/source/filter/excel/xeformula.cxx
 +++ sc/source/filter/excel/xeformula.cxx
 @@ -42,6 +42,12 @@
@@ -2758,7 +3052,7 @@
      switch( eTokType )
      {
          case svUnknown:     mbOk = false;                           break;
-@@ -1248,6 +1287,107 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
+@@ -1248,6 +1287,136 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
          ProcessFunction( rTokData, nExpClass );
  }
  
@@ -2772,7 +3066,6 @@
 +    {
 +        case svSingleRef:
 +        {
-+            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svSingleRef not supported yet\n");
 +            if (!mpScBasePos)
 +            {
 +                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
@@ -2780,22 +3073,22 @@
 +            }
 +            SingleRefData aRef(rTokData.mpScToken->GetSingleRef());
 +            aRef.CalcAbsIfRel(*mpScBasePos);
-+            ScToken* p = pRefMgr->getSingleRefToken(nFileId, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab), NULL);
++            const String& rTabName = rTokData.mpScToken->GetString();
++            ScToken* p = pRefMgr->getSingleRefToken(nFileId, rTabName, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab), NULL, NULL);
 +            if (!p)
 +            {
 +                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
 +                break;
 +            }
 +
-+            mpLinkMgr->StoreCell(nFileId, rTokData.mpScToken->GetString(), aRef);
++            mpLinkMgr->StoreCell(nFileId, rTabName, aRef);
 +
 +            XclAddress aXclPos(ScAddress::UNINITIALIZED);
 +            ConvertRefData(aRef, aXclPos, false, false, false);
 +
 +            const String* pFile = pRefMgr->getExternalFileName(nFileId);
 +            sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
-+            mpLinkMgr->FindExtSheet(nFileId, nExtSheet, nFirstSBTab, nLastSBTab, 
-+                                    aRef.nTab, aRef.nTab, GetNewRefLogEntry());
++            mpLinkMgr->FindExtSheet(nFileId, rTabName, 1, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry());
 +            sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
 +            AppendOpTokenId(GetTokenId(nBaseId, EXC_TOKCLASS_REF), nExpClass, rTokData.mnSpaces);
 +            Append(nExtSheet);
@@ -2810,13 +3103,43 @@
 +        break;
 +        case svDoubleRef:
 +        {
-+            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svDoubleRef not supported yet\n");
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   *** svDoubleRef support in progress ***\n");
 +            if (!mpScBasePos)
 +            {
 +                AppendErrorToken(XclTools::GetXclErrorCode(errNoRef), rTokData.mnSpaces);
 +                break;
 +            }
-+            AppendBoolToken(true, rTokData.mnSpaces);
++            ComplRefData aRef(rTokData.mpScToken->GetDoubleRef());
++            aRef.CalcAbsIfRel(*mpScBasePos);
++            const String& rTabName = rTokData.mpScToken->GetString();
++            const SingleRefData& r1 = aRef.Ref1;
++            const SingleRefData& r2 = aRef.Ref2;
++            ScRange aRange(r1.nCol, r1.nRow, r1.nTab, r2.nCol, r2.nRow, r2.nTab);
++            ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, aRange, NULL);
++            if (!pArray)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++
++            mpLinkMgr->StoreCellRange(nFileId, rTabName, aRef);
++            XclRange aXclRange(ScAddress::UNINITIALIZED);
++            ConvertRefData(aRef, aXclRange, false);
++            const String* pFile = pRefMgr->getExternalFileName(nFileId);
++            sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
++            sal_uInt16 nTabSpan = r2.nTab - r1.nTab + 1;
++            mpLinkMgr->FindExtSheet(nFileId, rTabName, nTabSpan, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry());
++
++            sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
++            AppendOpTokenId(GetTokenId( nBaseId, EXC_TOKCLASS_REF ), nExpClass, rTokData.mnSpaces);
++            Append(nExtSheet);
++            if (meBiff <= EXC_BIFF5)
++            {
++                Append(0, 8);
++                Append(static_cast<sal_uInt16>(nFirstSBTab));
++                Append(static_cast<sal_uInt16>(nLastSBTab));
++            }
++            AppendRange(aXclRange);
 +        }
 +        break;
 +        case svExternalName:
@@ -2866,7 +3189,7 @@
  void XclExpFmlaCompImpl::ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
  {
      OpCode eOpCode = rTokData.GetOpCode();
-@@ -1623,32 +1763,6 @@ void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData )
+@@ -1623,32 +1792,6 @@ void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData )
      }
  }
  
@@ -2900,10 +3223,10 @@
  
  SCTAB XclExpFmlaCompImpl::GetScTab( const SingleRefData& rRefData ) const
 diff --git sc/source/filter/excel/xelink.cxx sc/source/filter/excel/xelink.cxx
-index b1bacad..ebd2999 100644
+index b1bacad..4f1ed68 100644
 --- sc/source/filter/excel/xelink.cxx
 +++ sc/source/filter/excel/xelink.cxx
-@@ -38,6 +38,15 @@
+@@ -38,6 +38,40 @@
  #include "document.hxx"
  #include "cell.hxx"
  #include "scextopt.hxx"
@@ -2916,10 +3239,35 @@
 +using ::std::auto_ptr;
 +using ::std::find_if;
 +using ::std::vector;
++
++
++namespace {
++
++#include <string>
++
++class StackPrinter
++{
++public:
++    explicit StackPrinter(const char* msg) :
++        msMsg(msg)
++    {
++        fprintf(stdout, "%s: --begin\n", msMsg.c_str());
++    }
++
++    ~StackPrinter()
++    {
++        fprintf(stdout, "%s: --end\n", msMsg.c_str());
++    }
++
++private:
++    ::std::string msMsg;
++};
++
++}
  
  // ============================================================================
  // *** Helper classes ***
-@@ -102,6 +111,22 @@ private:
+@@ -102,6 +136,22 @@ private:
      XclExpCachedMatRef  mxMatrix;       /// Cached results of the DDE link.
  };
  
@@ -2942,7 +3290,7 @@
  // List of external names =====================================================
  
  /** List of all external names of a sheet. */
-@@ -117,6 +142,8 @@ public:
+@@ -117,6 +167,8 @@ public:
          @return  The 1-based (Excel-like) list index of the DDE link. */
      sal_uInt16          InsertDde( const String& rApplic, const String& rTopic, const String& rItem );
  
@@ -2951,7 +3299,7 @@
      /** Writes the EXTERNNAME record list. */
      virtual void        Save( XclExpStream& rStrm );
  
-@@ -220,6 +247,9 @@ public:
+@@ -220,6 +272,9 @@ public:
      /** Stores all cells in the given range in the CRN list. */
      void                StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange );
  
@@ -2961,19 +3309,20 @@
      /** Writes the XCT and all CRN records. */
      virtual void        Save( XclExpStream& rStrm );
  
-@@ -319,6 +349,11 @@ public:
+@@ -319,6 +374,12 @@ public:
      /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
      void                StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab );
  
 +    void                StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken );
 +    void                StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken );
 +
-+    sal_uInt16          GetTabIndex( const String& rTabName );
++    sal_uInt16          GetTabIndex( const String& rTabName ) const;
++    sal_uInt16          GetTabCount() const;
 +
      /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
      sal_uInt16          InsertTabName( const String& rTabName );
      /** Finds or inserts an EXTERNNAME record for add-ins.
-@@ -328,6 +363,8 @@ public:
+@@ -328,6 +389,8 @@ public:
          @return  The 1-based EXTERNNAME record index; or 0, if the record list is full. */
      sal_uInt16          InsertDde( const String& rItem );
  
@@ -2982,7 +3331,7 @@
      /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
      virtual void        Save( XclExpStream& rStrm );
  
-@@ -394,6 +431,9 @@ public:
+@@ -394,6 +457,9 @@ public:
      /** Stores all cells in the given range in a CRN record list. */
      void                StoreCellRange( const ScRange& rRange );
  
@@ -2992,7 +3341,7 @@
      /** Finds or inserts an EXTERNNAME record for an add-in function name.
          @param rnSupbook  Returns the index of the SUPBOOK record which contains the add-in function name.
          @param rnExtName  Returns the 1-based EXTERNNAME record index. */
-@@ -407,9 +447,25 @@ public:
+@@ -407,9 +473,25 @@ public:
                              sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem );
  
@@ -3000,7 +3349,7 @@
 +                            sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
 +                            const String& rName, const ScTokenArray* pArray );
 +
-+    XclExpXti           GetXti( sal_uInt16 nFileId, sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
++    XclExpXti           GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
 +                                XclExpRefLogEntry* pRefLogEntry = NULL );
 +
      /** Writes all SUPBOOK records with their sub records. */
@@ -3018,8 +3367,12 @@
  private:
      typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
      typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
-@@ -435,15 +491,6 @@ private:
-     void                AddExtSupbook( SCTAB nScTab );
+@@ -431,19 +513,8 @@ private:
+     /** Appends a new SUPBOOK to the list.
+         @return  The list index of the SUPBOOK record. */
+     sal_uInt16          Append( XclExpSupbookRef xSupbook );
+-    /** Creates and appends an external SUPBOOK record from the Calc sheet nScTab. */
+-    void                AddExtSupbook( SCTAB nScTab );
  
  private:
 -    struct XclExpSBIndex
@@ -3034,13 +3387,12 @@
      XclExpSupbookList   maSupbookList;      /// List of all SUPBOOK records.
      XclExpSBIndexVec    maSBIndexVec;       /// SUPBOOK and sheet name index for each Excel sheet.
      sal_uInt16          mnOwnDocSB;         /// Index to SUPBOOK for own document.
-@@ -464,9 +511,17 @@ public:
+@@ -464,9 +535,16 @@ public:
      /** Derived classes search for a special EXTERNSHEET index for the own document. */
      virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) = 0;
  
-+    virtual void FindExtSheet( sal_uInt16 nFileId, sal_uInt16& rnExtSheet, 
-+                               sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
-+                               sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
 +                               XclExpRefLogEntry* pRefLogEntry ) = 0;
 +
      /** Derived classes store all cells in the given range in a CRN record list. */
@@ -3052,7 +3404,7 @@
      /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
      virtual bool        InsertAddIn(
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
-@@ -476,6 +531,10 @@ public:
+@@ -476,6 +554,10 @@ public:
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem ) = 0;
  
@@ -3063,13 +3415,12 @@
      /** Derived classes write the entire link table to the passed stream. */
      virtual void        Save( XclExpStream& rStrm ) = 0;
  
-@@ -497,15 +556,28 @@ public:
+@@ -497,15 +579,27 @@ public:
                              XclExpRefLogEntry* pRefLogEntry );
      virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
  
-+    virtual void FindExtSheet( sal_uInt16 nFileId, sal_uInt16& rnExtSheet, 
-+                               sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
-+                               sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
 +                               XclExpRefLogEntry* pRefLogEntry );
 +
      virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
@@ -3092,13 +3443,12 @@
      virtual void        Save( XclExpStream& rStrm );
  
  private:
-@@ -550,15 +622,28 @@ public:
+@@ -550,15 +644,27 @@ public:
                              XclExpRefLogEntry* pRefLogEntry );
      virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
  
-+    virtual void FindExtSheet( sal_uInt16 nFileId, sal_uInt16& rnExtSheet, 
-+                               sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
-+                               sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
 +                               XclExpRefLogEntry* pRefLogEntry );
 +
      virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
@@ -3121,7 +3471,7 @@
      virtual void        Save( XclExpStream& rStrm );
  
  private:
-@@ -885,6 +970,94 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
+@@ -885,6 +991,94 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
          mxMatrix->Save( rStrm );
  }
  
@@ -3216,7 +3566,7 @@
  // List of external names =====================================================
  
  XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
-@@ -920,6 +1093,12 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde(
+@@ -920,6 +1114,12 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde(
      return nIndex;
  }
  
@@ -3229,7 +3579,7 @@
  void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
  {
      maNameList.Save( rStrm );
-@@ -1066,6 +1245,78 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
+@@ -1066,6 +1266,83 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
      maUsedCells.SetMultiMarkArea( rRange );
  }
  
@@ -3263,6 +3613,7 @@
 +
 +void XclExpXct::StoreCellRange( const XclExpRoot& /*rRoot*/, const ScRange& rRange, const ScToken& rToken )
 +{
++    StackPrinter __stack_print__("XclExpXct::StoreCellRange");
 +    if (rToken.GetType() != svMatrix)
 +        return;
 +
@@ -3294,12 +3645,16 @@
 +                XclExpCrnRef xCrn(new XclExpCrnString(
 +                    s.Col() + nCol, s.Row() + nRow, pMtx->GetString(nCol, nRow)));
 +                maCrnList.AppendRecord(xCrn);
++                fprintf(stdout, "XclExpXct::StoreCellRange:   storing at (col=%d; row=%d) (%s)\n", 
++                        s.Col()+nCol, s.Row()+nRow, rtl::OUStringToOString(pMtx->GetString(nCol, nRow), RTL_TEXTENCODING_UTF8).getStr());
 +            }
 +            else if (pMtx->IsValueOrEmpty(nCol, nRow))
 +            {
 +                XclExpCrnRef xCrn(new XclExpCrnDouble(
 +                    s.Col() + nCol, s.Row() + nRow, pMtx->GetDouble(nCol, nRow)));
 +                maCrnList.AppendRecord(xCrn);
++                fprintf(stdout, "XclExpXct::StoreCellRange:   storing at (col=%d; row=%d) (%g)\n",
++                        s.Col()+nCol, s.Row()+nRow, pMtx->GetDouble(nCol, nRow));
 +            }
 +        }
 +    }
@@ -3308,7 +3663,29 @@
  void XclExpXct::Save( XclExpStream& rStrm )
  {
      XclExpRecord::Save( rStrm );
-@@ -1206,6 +1457,41 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+@@ -1168,6 +1445,21 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) :
+     mnXclTabCount( 0 )
+ {
+     SetRecSize( 2 + maUrlEncoded.GetSize() );
++
++    // We need to create all tables up front to ensure the correct table order.
++    ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
++    const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++    if (!pTabNames)
++        return;
++
++    vector<String>::const_iterator itr = pTabNames->begin(), itrEnd = pTabNames->end();
++    for (; itr != itrEnd; ++itr)
++    {
++        fprintf(stdout, "XclExpSupbook::InsertTabName:   name = '%s'\n", 
++                rtl::OUStringToOString(*itr, RTL_TEXTENCODING_UTF8).getStr());
++        InsertTabName(*itr);
++    }
+ }
+ 
+ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) :
+@@ -1206,6 +1498,46 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
          xXct->StoreCellRange( GetRoot(), rRange );
  }
  
@@ -3334,7 +3711,7 @@
 +    xXct->StoreCellRange(GetRoot(), rRange, rToken);
 +}
 +
-+sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName )
++sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName ) const
 +{
 +    XclExpString aXclName(rTabName);
 +    size_t nSize = maXctList.GetSize();
@@ -3344,13 +3721,18 @@
 +        if (aXclName == aRec->GetTabName())
 +            return ulimit_cast<sal_uInt16>(i);
 +    }
-+    return InsertTabName(rTabName);
++    return EXC_NOTAB;
++}
++
++sal_uInt16 XclExpSupbook::GetTabCount() const
++{
++    return ulimit_cast<sal_uInt16>(maXctList.GetSize());
 +}
 +
  sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName )
  {
      DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
-@@ -1226,6 +1512,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
+@@ -1226,6 +1558,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
      return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
  }
  
@@ -3362,7 +3744,19 @@
  void XclExpSupbook::Save( XclExpStream& rStrm )
  {
      // SUPBOOK record
-@@ -1352,6 +1643,135 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+@@ -1289,11 +1626,6 @@ XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+         mnOwnDocSB = Append( xSupbook );
+         for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
+             maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
+-
+-        // add SUPBOOKs with external references
+-        for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
+-            if( rTabInfo.IsExternalTab( nScTab ) )
+-                AddExtSupbook( nScTab );
+     }
+ }
+ 
+@@ -1352,6 +1684,135 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
      }
  }
  
@@ -3405,11 +3799,11 @@
 +    if (!pToken)
 +        return;
 +
-+//  const String* pTabName = pRefMgr->getExternalTableName(nFileId, rCell.Tab());
-+//  if (!pTabName)
-+//      return;
-+
 +    sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
++    if (nSheetId == EXC_NOTAB)
++        // specified table name not found in this SUPBOOK.
++        return;
++
 +    FindSBIndexEntry f(nSupbookId, nSheetId);
 +    fprintf(stdout, "XclExpSupbookBuffer::StoreCell: supbook id = %d; sheet id = %d\n", nSupbookId, nSheetId);
 +    XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
@@ -3427,6 +3821,8 @@
 +
 +void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange )
 +{
++    StackPrinter __stack_print__("XclExpSupbookBuffer::StoreCellRange");
++
 +    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
 +    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
 +    if (!pUrl)
@@ -3446,12 +3842,13 @@
 +    // If this is a multi-table range, get token for each table.
 +    vector<ScToken*> aMatrixList;
 +    aMatrixList.reserve(nTabCount);
++
++    // This is a new'ed instance, so we must manage its life cycle here.
 +    ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
 +    if (!pArray)
 +        return;
 +
-+    auto_ptr<ScTokenArray> pNew(pArray->Clone());
-+    for (ScToken* p = pNew->First(); p; p = pNew->Next())
++    for (ScToken* p = pArray->First(); p; p = pArray->Next())
 +    {
 +        if (p->GetType() == svMatrix)
 +            aMatrixList.push_back(p);
@@ -3475,10 +3872,6 @@
 +    aRange.aEnd.SetTab(0);
 +    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
 +    {
-+        const String* pTabName = pRefMgr->getExternalTableName(nFileId, nTab);
-+        if (!pTabName)
-+            continue;
-+
 +        sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab);
 +        FindSBIndexEntry f(nSupbookId, nSheetId);
 +        XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
@@ -3491,6 +3884,7 @@
 +            r.mnSBTab   = nSheetId;
 +        }
 +
++        fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   supbook sheet id = %d\n", nSheetId);
 +        xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab-nTab1]);
 +    }
 +}
@@ -3498,7 +3892,7 @@
  bool XclExpSupbookBuffer::InsertAddIn(
          sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1383,6 +1803,72 @@ bool XclExpSupbookBuffer::InsertDde(
+@@ -1383,6 +1844,83 @@ bool XclExpSupbookBuffer::InsertDde(
      return rnExtName > 0;
  }
  
@@ -3516,9 +3910,13 @@
 +    return rnExtName > 0;
 +}
 +
-+XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
++XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
 +                                       XclExpRefLogEntry* pRefLogEntry )
 +{
++    StackPrinter __stack_print__("XclExpSupbookBuffer::GetXti");
++    fprintf(stdout, "XclExpSupbookBuffer::GetXti:   tab name = '%s'; tab span = %d\n",
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr(), nXclTabSpan);
++
 +    XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB);
 +    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
 +    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
@@ -3534,13 +3932,20 @@
 +    }
 +    aXti.mnSupbook = nSupbookId;
 +
-+    for (sal_uInt16 nTab = nFirstXclTab; nTab <= nLastXclTab; ++nTab)
++    sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
++    if (nFirstSheetId == EXC_NOTAB)
++    {
++        fprintf(stdout, "XclExpSupbookBuffer::GetXti:   first sheet not found in SUPBOOK (%s)\n", 
++                rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++        return aXti;
++    }
++    sal_uInt16 nSheetCount = xSupbook->GetTabCount();
++    for (sal_uInt16 i = 0; i < nXclTabSpan; ++i)
 +    {
-+        const String* pTabName = pRefMgr->getExternalTableName(nFileId, nTab);
-+        if (!pTabName)
-+            continue;
++        sal_uInt16 nSheetId = nFirstSheetId + i;
++        if (nSheetId >= nSheetCount)
++            return aXti;
 +
-+        sal_uInt16 nSheetId = xSupbook->GetTabIndex(*pTabName);
 +        FindSBIndexEntry f(nSupbookId, nSheetId);
 +        XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
 +        XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
@@ -3551,16 +3956,16 @@
 +            r.mnSupbook = nSupbookId;
 +            r.mnSBTab   = nSheetId;
 +        }
-+        if (nTab == nFirstXclTab)
++        if (i == 0)
 +            aXti.mnFirstSBTab = nSheetId;
-+        if (nTab == nLastXclTab)
++        if (i == nXclTabSpan - 1)
 +            aXti.mnLastSBTab = nSheetId;
 +    }
 +
 +    if (pRefLogEntry)
 +    {
-+        pRefLogEntry->mnFirstXclTab = nFirstXclTab;
-+        pRefLogEntry->mnLastXclTab  = nLastXclTab;
++        pRefLogEntry->mnFirstXclTab = 0;
++        pRefLogEntry->mnLastXclTab  = 0;
 +        if (xSupbook.is())
 +            xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
 +    }
@@ -3571,13 +3976,42 @@
  void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
  {
      maSupbookList.Save( rStrm );
-@@ -1485,11 +1971,28 @@ sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
+@@ -1424,27 +1962,6 @@ sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
+     return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
+ }
+ 
+-void XclExpSupbookBuffer::AddExtSupbook( SCTAB nScTab )
+-{
+-    sal_uInt16 nXclTab = GetTabInfo().GetXclTab( nScTab );
+-    DBG_ASSERT( nXclTab < maSBIndexVec.size(), "XclExpSupbookBuffer::AddExtSupbook - out of range" );
+-
+-    // find ext doc name or append new one, save position in maSBIndexBuffer
+-    const String& rUrl = GetDoc().GetLinkDoc( nScTab );
+-    DBG_ASSERT( rUrl.Len(), "XclExpSupbookBuffer::AddExtSupbook - missing external linked sheet" );
+-    sal_uInt16 nSupbook;
+-    XclExpSupbookRef xSupbook;
+-    if( !GetSupbookUrl( xSupbook, nSupbook, rUrl ) )
+-    {
+-        xSupbook.reset( new XclExpSupbook( GetRoot(), rUrl ) );
+-        nSupbook = Append( xSupbook );
+-    }
+-
+-    // append new sheet name, save SUPBOOK and sheet position in maSBIndexVec
+-    maSBIndexVec[ nXclTab ].mnSupbook = nSupbook;
+-    maSBIndexVec[ nXclTab ].mnSBTab = xSupbook->InsertTabName( GetDoc().GetLinkTab( nScTab ) );
+-}
+-
+ // Export link manager ========================================================
+ 
+ XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
+@@ -1485,11 +2002,29 @@ sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
      return nExtSheet;
  }
  
 +void XclExpLinkManagerImpl5::FindExtSheet( 
-+    sal_uInt16 /*nFileId*/, sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/, 
-+    sal_uInt16 /*nFirstXclTab*/, sal_uInt16 /*nLastXclTab*/, XclExpRefLogEntry* /*pRefLogEntry*/ )
++    sal_uInt16 /*nFileId*/, const String& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/, 
++    sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/, 
++    XclExpRefLogEntry* /*pRefLogEntry*/ )
 +{
 +    // not implemented
 +}
@@ -3600,7 +4034,7 @@
  bool XclExpLinkManagerImpl5::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1510,6 +2013,14 @@ bool XclExpLinkManagerImpl5::InsertDde(
+@@ -1510,6 +2045,14 @@ bool XclExpLinkManagerImpl5::InsertDde(
      return false;
  }
  
@@ -3615,15 +4049,16 @@
  void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
  {
      if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
-@@ -1630,6 +2141,16 @@ sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
+@@ -1630,6 +2173,17 @@ sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
      return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
  }
  
 +void XclExpLinkManagerImpl8::FindExtSheet( 
-+    sal_uInt16 nFileId, sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
-+    sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, XclExpRefLogEntry* pRefLogEntry )
++    sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, 
++    sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++    XclExpRefLogEntry* pRefLogEntry )
 +{
-+    XclExpXti aXti = maSBBuffer.GetXti(nFileId, nFirstXclTab, nLastXclTab, pRefLogEntry);
++    XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, pRefLogEntry);
 +    rnExtSheet = InsertXti(aXti);
 +    rnFirstSBTab = aXti.mnFirstSBTab;
 +    rnLastSBTab  = aXti.mnLastSBTab;
@@ -3632,7 +4067,7 @@
  void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 )
  {
      if( !rRef1.IsDeleted() && !rRef2.IsDeleted() && (rRef1.nTab >= 0) && (rRef2.nTab >= 0) )
-@@ -1652,6 +2173,19 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
+@@ -1652,6 +2206,19 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
      }
  }
  
@@ -3652,7 +4087,7 @@
  bool XclExpLinkManagerImpl8::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1677,6 +2211,18 @@ bool XclExpLinkManagerImpl8::InsertDde(
+@@ -1677,6 +2244,18 @@ bool XclExpLinkManagerImpl8::InsertDde(
      return false;
  }
  
@@ -3671,22 +4106,21 @@
  void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
  {
      if( !maXtiVec.empty() )
-@@ -1745,6 +2291,14 @@ sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
+@@ -1745,6 +2324,13 @@ sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
      return mxImpl->FindExtSheet( cCode );
  }
  
-+void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, sal_uInt16& rnExtSheet, 
-+                                      sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
-+                                      sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, 
++void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                      sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
 +                                      XclExpRefLogEntry* pRefLogEntry )
 +{
-+    mxImpl->FindExtSheet( nFileId, rnExtSheet, rnFirstSBTab, rnLastSBTab, nFirstXclTab, nLastXclTab, pRefLogEntry );
++    mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry );
 +}
 +
  void XclExpLinkManager::StoreCell( const SingleRefData& rRef )
  {
      mxImpl->StoreCellRange( rRef, rRef );
-@@ -1755,6 +2309,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
+@@ -1755,6 +2341,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
      mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
  }
  
@@ -3703,7 +4137,7 @@
  bool XclExpLinkManager::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1768,6 +2332,13 @@ bool XclExpLinkManager::InsertDde(
+@@ -1768,6 +2364,13 @@ bool XclExpLinkManager::InsertDde(
      return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
  }
  
@@ -3718,13 +4152,20 @@
  {
      mxImpl->Save( rStrm );
 diff --git sc/source/filter/excel/xilink.cxx sc/source/filter/excel/xilink.cxx
-index 01932a5..38b846b 100644
+index 01932a5..ae4623c 100644
 --- sc/source/filter/excel/xilink.cxx
 +++ sc/source/filter/excel/xilink.cxx
-@@ -39,6 +39,31 @@
+@@ -38,6 +38,37 @@
+ #include "xistream.hxx"
  #include "xihelper.hxx"
  #include "xiname.hxx"
- 
++#include "excform.hxx"
++#include "tokenarray.hxx"
++#include "externalrefmgr.hxx"
++
++#include <vector>
++
++using ::std::vector;
 +
 +namespace {
 +
@@ -3749,14 +4190,15 @@
 +};
 +
 +}
-+
+ 
  // ============================================================================
  // *** Helper classes ***
- // ============================================================================
-@@ -52,8 +77,10 @@ public:
+@@ -52,8 +83,12 @@ public:
      /** Reads a cached value and stores it with its cell address. */
      explicit            XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
  
++    const XclAddress&   GetAddress() const;
++
 +#if 0
      /** Copies the cached value to sheet nTab in the document. */
      void                SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const;
@@ -3764,7 +4206,14 @@
  
  private:
      XclAddress          maXclPos;       /// Excel position of the cached cell.
-@@ -76,11 +103,13 @@ public:
+@@ -71,16 +106,21 @@ public:
+                         ~XclImpSupbookTab();
+ 
+     inline const String& GetTabName() const { return maTabName; }
++#if 0
+     inline SCTAB        GetScTab() const { return mnScTab; }
+-
++#endif
      /** Reads a CRN record (external referenced cell) at the specified address. */
      void                ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
  
@@ -3775,10 +4224,20 @@
                              const XclImpRoot& rRoot, const String& rAbsUrl,
                              const String& rFilterName, const String& rFilterOpt );
 +#endif
++
++    void                LoadCachedValues(ScExternalRefCache::Table* pCacheTable);
  
  private:
      typedef ScfDelList< XclImpCrn > XclImpCrnList;
-@@ -112,11 +141,13 @@ public:
+@@ -105,18 +145,20 @@ public:
+     /** Reads a CRN record (external referenced cell). */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns the SUPBOOK record type. */
+     inline XclSupbookType GetType() const { return meType; }
  
      /** Returns the URL of the external document. */
      inline const String& GetXclUrl() const { return maXclUrl; }
@@ -3793,22 +4252,35 @@
  
      /** Returns the external name specified by an index from the Excel document (one-based). */
      const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
-@@ -128,10 +159,14 @@ public:
+@@ -128,10 +170,18 @@ public:
      /** Returns the specified macro name (1-based) or an empty string on error. */
      const String&       GetMacroName( sal_uInt16 nXclNameIdx ) const;
  
 +    const String&       GetTabName( sal_uInt16 nXtiTab ) const;
 +
++    sal_uInt16          GetTabCount() const;
++
 +#if 0
      /** Creates all sheets of this external document.
          @param nFirstTab  The external Excel index of the first sheet to be created.
          @param nLastTab  The external Excel index of the last sheet to be created. */
      void                CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast );
 +#endif
++
++    void                LoadCachedValues();
  
  private:
      typedef ScfDelList< XclImpSupbookTab >  XclImpSupbookTabList;
-@@ -191,6 +226,13 @@ public:
+@@ -180,7 +230,7 @@ public:
+     /** Reads a CRN record and appends it to the current SUPBOOK. */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns true, if the specified XTI entry contains an internal reference. */
+     bool                IsSelfRef( sal_uInt16 nXtiIndex ) const;
+@@ -191,6 +241,13 @@ public:
                              sal_uInt16 nXtiIndex ) const;
      /** Returns the specified external name or 0 on error. */
      const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
@@ -3822,7 +4294,7 @@
      /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
          @descr  For DDE links: Decodes to application name and topic.
          For OLE object links: Decodes to class name and document URL.
-@@ -198,19 +240,23 @@ public:
+@@ -198,19 +255,23 @@ public:
      bool                GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const;
      /** Returns the specified macro name or an empty string on error. */
      const String&       GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
@@ -3848,15 +4320,88 @@
  
      /** Finds the largest range of sheet indexes in a SUPBOOK after a start sheet index.
          @param rnSBTabFirst  (out-param) The first sheet index of the range in SUPBOOK is returned here.
-@@ -341,6 +387,7 @@ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
+@@ -291,13 +352,16 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa
+ 
+ // External names =============================================================
+ 
+-XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn )
++XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn, ExcelToSc* pFormulaConv )
+ {
++    StackPrinter __stack_print__("XclImpExtName::XclImpExtName");
+     sal_uInt16 nFlags;
+     sal_uInt8 nLen;
+ 
+     rStrm >> nFlags >> mnStorageId >> nLen ;
+     maName = rStrm.ReadUniString( nLen );
++    fprintf(stdout, "XclImpExtName::XclImpExtName:   flags = 0x%2.2X; storage id = %d; name = '%s'\n",
++            nFlags, mnStorageId, rtl::OUStringToOString(maName, RTL_TEXTENCODING_UTF8).getStr());
+ 
+     if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
+     {
+@@ -319,6 +383,35 @@ XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn )
+ 
+     if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) )
+         mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) );
++
++    if (meType == xlExtName)
++    {
++        if (mnStorageId == 0)
++        {
++            fprintf(stdout, "XclImpExtName::XclImpExtName:   global external name\n");
++            if (pFormulaConv)
++            {
++                const ScTokenArray* pArray = NULL;
++                sal_uInt16 nFmlaLen;
++                rStrm >> nFmlaLen;
++                vector<String> aTabNames;
++                sal_uInt16 nCount = rSupbook.GetTabCount();
++                fprintf(stdout, "XclImpExtName::XclImpExtName:   tab count = %d\n", nCount);
++                aTabNames.reserve(nCount);
++                for (sal_uInt16 i = 0; i < nCount; ++i)
++                    aTabNames.push_back(rSupbook.GetTabName(i));
++
++                pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
++                if (pArray)
++                {
++                    fprintf(stdout, "XclImpExtName::XclImpExtName:   formula token processed\n");    
++                    mxArray.reset(pArray->Clone());
++                }
++            }
++        }
++        else
++            fprintf(stdout, "XclImpExtName::XclImpExtName:   external name for sheet %ld\n", mnStorageId);
++    }
+ }
+ 
+ XclImpExtName::~XclImpExtName()
+@@ -333,6 +426,13 @@ void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, cons
+     rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
+ }
+ 
++void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
++{
++    StackPrinter __stack_print__("XclImpExtName::CreateExtNameData");
++    ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
++    pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
++}
++
+ // Cached external cells ======================================================
+ 
+ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
+@@ -341,6 +441,12 @@ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
  {
  }
  
++const XclAddress& XclImpCrn::GetAddress() const
++{
++    return maXclPos;
++}
++
 +#if 0
  void XclImpCrn::SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const
  {
      ScAddress aScPos( ScAddress::UNINITIALIZED );
-@@ -365,6 +412,7 @@ void XclImpCrn::SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const
+@@ -365,6 +471,7 @@ void XclImpCrn::SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const
          }
      }
  }
@@ -3864,7 +4409,7 @@
  
  // Sheet in an external document ==============================================
  
-@@ -383,6 +431,7 @@ void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
+@@ -383,6 +490,7 @@ void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
      maCrnList.Append( new XclImpCrn( rStrm, rXclPos ) );
  }
  
@@ -3872,17 +4417,71 @@
  void XclImpSupbookTab::CreateAndFillTable( const XclImpRoot& rRoot,
          const String& rAbsUrl, const String& rFilterName, const String& rFilterOpt )
  {
-@@ -391,6 +440,7 @@ void XclImpSupbookTab::CreateAndFillTable( const XclImpRoot& rRoot,
+@@ -391,6 +499,53 @@ void XclImpSupbookTab::CreateAndFillTable( const XclImpRoot& rRoot,
              for( const XclImpCrn* pCrn = maCrnList.First(); pCrn; pCrn = maCrnList.Next() )
                  pCrn->SetCell( rRoot, mnScTab );
  }
 +#endif
++
++void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::Table* pCacheTable)
++{
++    StackPrinter __stack_print__("XclImpSupbookTab::LoadCachedValues");
++    if (maCrnList.Empty())
++    {
++        fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   no CRN record to speak of\n");
++        return;
++    }
++
++    for (XclImpCrn* p = maCrnList.First(); p; p = maCrnList.Next())
++    {
++        const XclAddress& rAddr = p->GetAddress();
++        fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   col = %d; row = %d\n", rAddr.mnCol, rAddr.mnRow);
++        switch (p->GetType())
++        {
++            case EXC_CACHEDVAL_BOOL:
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   bool\n");
++            break;
++            case EXC_CACHEDVAL_DOUBLE:
++            {
++                double f = p->GetValue();
++                ScExternalRefCache::TokenRef pToken(new ScDoubleToken(f));
++                pCacheTable->setCell(rAddr.mnRow, rAddr.mnCol, pToken);
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   double (%g)\n", f);
++            }
++            break;
++            case EXC_CACHEDVAL_EMPTY:
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   empty\n");
++            break;
++            case EXC_CACHEDVAL_ERROR:
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   error\n");
++            break;
++            case EXC_CACHEDVAL_STRING:
++            {
++                const String& rStr = p->GetString();
++                ScExternalRefCache::TokenRef pToken(new ScStringToken(rStr));
++                pCacheTable->setCell(rAddr.mnRow, rAddr.mnCol, pToken);
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   string (%s)\n", rtl::OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr());
++            }
++            break;
++            default:
++                fprintf(stdout, "XclImpSupbookTab::LoadCachedValues:   other type\n");
++        }
++    }
++}
  
  // External document (SUPBOOK) ================================================
  
-@@ -457,13 +507,14 @@ void XclImpSupbook::ReadExternname( XclImpStream& rStrm )
+@@ -453,17 +608,20 @@ void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
+     }
+ }
+ 
+-void XclImpSupbook::ReadExternname( XclImpStream& rStrm )
++void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
  {
-     maExtNameList.Append( new XclImpExtName( rStrm, meType == EXC_SBTYPE_ADDIN ) );
+-    maExtNameList.Append( new XclImpExtName( rStrm, meType == EXC_SBTYPE_ADDIN ) );
++    StackPrinter __stack_print__("XclImpSupbook::ReadExternname");
++    fprintf(stdout, "XclImpSupbook::ReadExternname:   tab count = %ld %ld\n", GetTabCount(), maSupbTabList.Count());
++    maExtNameList.Append( new XclImpExtName( *this, rStrm, meType == EXC_SBTYPE_ADDIN, pFormulaConv ) );
  }
 -
 +#if 0
@@ -3898,7 +4497,7 @@
  }
  
  SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
-@@ -473,6 +524,15 @@ SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
+@@ -473,6 +631,15 @@ SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
              return pSBTab->GetScTab();
      return SCTAB_INVALID;
  }
@@ -3914,7 +4513,7 @@
  
  const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
  {
-@@ -492,6 +552,22 @@ const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
+@@ -492,6 +659,27 @@ const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
      return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
  }
  
@@ -3933,19 +4532,60 @@
 +    return EMPTY_STRING;
 +}
 +
++sal_uInt16 XclImpSupbook::GetTabCount() const
++{
++    return ulimit_cast<sal_uInt16>(maSupbTabList.Count());
++}
++
 +#if 0
  void XclImpSupbook::CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast )
  {
      if( (meType == EXC_SBTYPE_EXTERN) && (GetExtDocOptions().GetDocSettings().mnLinkCnt == 0) && GetDocShell() )
-@@ -508,6 +584,7 @@ void XclImpSupbook::CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast
+@@ -508,6 +696,43 @@ void XclImpSupbook::CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast
                  pSBTab->CreateAndFillTable( GetRoot(), aAbsUrl, maFilterName, maFilterOpt );
      }
  }
 +#endif
++
++void XclImpSupbook::LoadCachedValues()
++{
++    StackPrinter __stack_print__("XclImpSupbook::LoadCachedValues");
++    if (meType == EXC_SBTYPE_SELF)
++        fprintf(stdout, "XclImpSupbook::LoadCachedValues:   internal book\n");
++
++    if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0)
++    {
++        fprintf(stdout, "XclImpSupbook::LoadCachedValues:   don't load cached values\n");
++        return;
++    }
++
++    String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
++    fprintf(stdout, "XclImpSupbook::LoadCachedValues:   doc url = '%s'\n", 
++            rtl::OUStringToOString(aAbsUrl, RTL_TEXTENCODING_UTF8).getStr());
++
++    ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
++
++    sal_uInt16 nCount = maSupbTabList.Count();
++    for (sal_uInt16 i = 0; i < nCount; ++i)
++    {
++        XclImpSupbookTab* pTab = maSupbTabList.GetObject(i);
++        if (!pTab)
++        {
++            fprintf(stdout, "XclImpSupbook::LoadCachedValues:   supbook table instance is NULL!\n");
++            return;
++        }
++        
++        const String& rTabName = pTab->GetTabName();
++        fprintf(stdout, "XclImpSupbook::LoadCachedValues:   tab name = '%s'\n", rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++        ScExternalRefCache::Table* pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName);
++        pTab->LoadCachedValues(pCacheTable);
++    }
++}
  
  // Import link manager ========================================================
  
-@@ -531,7 +608,7 @@ void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
+@@ -531,7 +756,7 @@ void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
          --nXtiCount;
      }
  
@@ -3954,7 +4594,20 @@
  }
  
  void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
-@@ -570,8 +647,8 @@ bool XclImpLinkManagerImpl::GetScTabRange(
+@@ -551,10 +776,10 @@ void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
+         pSupbook->ReadCrn( rStrm );
+ }
+ 
+-void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm )
++void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+ {
+     if( XclImpSupbook* pSupbook = maSupbookList.Last() )
+-        pSupbook->ReadExternname( rStrm );
++        pSupbook->ReadExternname( rStrm, pFormulaConv );
+ }
+ 
+ bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
+@@ -570,8 +795,8 @@ bool XclImpLinkManagerImpl::GetScTabRange(
      {
          if( const XclImpSupbook* pSupbook = maSupbookList.GetObject( pXti->mnSupbook ) )
          {
@@ -3965,7 +4618,7 @@
              return true;
          }
      }
-@@ -584,6 +661,20 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex,
+@@ -584,6 +809,20 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex,
      return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
  }
  
@@ -3986,7 +4639,7 @@
  bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
  {
      const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
-@@ -595,12 +686,18 @@ const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uIn
+@@ -595,12 +834,18 @@ const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uIn
      const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
      return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
  }
@@ -4006,7 +4659,7 @@
  
  const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt32 nXtiIndex ) const
  {
-@@ -616,6 +713,7 @@ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) con
+@@ -616,6 +861,7 @@ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) con
      return 0;
  }
  
@@ -4014,7 +4667,7 @@
  void XclImpLinkManagerImpl::CreateTables()
  {
      DBG_ASSERT( !mbCreated, "XclImpLinkManager::CreateTables - multiple call" );
-@@ -637,6 +735,15 @@ void XclImpLinkManagerImpl::CreateTables()
+@@ -637,6 +883,21 @@ void XclImpLinkManagerImpl::CreateTables()
      }
      mbCreated = true;
  }
@@ -4022,15 +4675,33 @@
 +
 +void XclImpLinkManagerImpl::LoadCachedValues()
 +{
++    StackPrinter __stack_print__("XclImpLinkManagerImpl::LoadCachedValues");
 +    // Read all CRN records which can be accessed via XclImpSupbook, and store 
 +    // the cached values to the external reference manager.
 +
-+    // TODO: Implement this.
++    sal_uInt32 nCount = maSupbookList.Count();
++    for (sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook)
++    {
++        XclImpSupbook* pSupbook = maSupbookList.GetObject(nSupbook);
++        pSupbook->LoadCachedValues();
++    }
 +}
  
  bool XclImpLinkManagerImpl::FindNextTabRange(
          sal_uInt16& rnSBTabFirst, sal_uInt16& rnSBTabLast,
-@@ -707,6 +814,16 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal
+@@ -686,9 +947,9 @@ void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
+     mxImpl->ReadCrn( rStrm );
+ }
+ 
+-void XclImpLinkManager::ReadExternname( XclImpStream& rStrm )
++void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+ {
+-    mxImpl->ReadExternname( rStrm );
++    mxImpl->ReadExternname( rStrm, pFormulaConv );
+ }
+ 
+ bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
+@@ -707,6 +968,16 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal
      return mxImpl->GetExternName( nXtiIndex, nExtName );
  }
  
@@ -4047,7 +4718,7 @@
  bool XclImpLinkManager::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
  {
      return mxImpl->GetLinkData( rApplic, rTopic, nXtiIndex );
-@@ -716,11 +833,16 @@ const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16
+@@ -716,11 +987,16 @@ const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16
  {
      return mxImpl->GetMacroName( nExtSheet, nExtName );
  }
@@ -4079,10 +4750,29 @@
  public:
  	inline						XclImpChTrFmlConverter(
 diff --git sc/source/filter/inc/excform.hxx sc/source/filter/inc/excform.hxx
-index 915dd98..6913b25 100644
+index 915dd98..1b36638 100644
 --- sc/source/filter/inc/excform.hxx
 +++ sc/source/filter/inc/excform.hxx
-@@ -113,8 +113,9 @@ private:
+@@ -35,6 +35,7 @@
+ #include "xiroot.hxx"
+ #include "formel.hxx"
+ 
++#include <vector>
+ 
+ class ScRangeList;
+ 
+@@ -64,6 +65,10 @@ public:
+                                  bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula );
+ 
+     virtual ConvErr     Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula );
++
++    virtual ConvErr     ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                           const String& rUrl, const ::std::vector<String>& rTabNames );
++
+     virtual BOOL        GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen );
+ 
+ 	void				GetDummy( const ScTokenArray*& );
+@@ -113,8 +118,9 @@ private:
      void                ExcRelToScRel8( UINT16 nRow, UINT16 nCol, SingleRefData&,
  							const BOOL bName );
  
@@ -4094,6 +4784,16 @@
  
  public:
                          ExcelToSc8( const XclImpRoot& rRoot );
+@@ -124,6 +130,9 @@ public:
+ 
+     virtual ConvErr     Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula );
+ 
++    virtual ConvErr     ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                           const String& rUrl, const ::std::vector<String>& rTabNames );
++
+ 	static inline BOOL	IsComplRowRange( const UINT16 nRow1, const UINT16 nRow2 );
+ 
+     virtual BOOL        GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen );
 diff --git sc/source/filter/inc/fdumper.hxx sc/source/filter/inc/fdumper.hxx
 index aea8de6..8f57403 100644
 --- sc/source/filter/inc/fdumper.hxx
@@ -4202,16 +4902,15 @@
  #endif
  
 diff --git sc/source/filter/inc/xelink.hxx sc/source/filter/inc/xelink.hxx
-index 795219c..53e864f 100644
+index 795219c..ee53c3a 100644
 --- sc/source/filter/inc/xelink.hxx
 +++ sc/source/filter/inc/xelink.hxx
-@@ -173,11 +173,20 @@ public:
+@@ -173,11 +173,19 @@ public:
      /** Searches for a special EXTERNSHEET index for the own document. */
      sal_uInt16          FindExtSheet( sal_Unicode cCode );
  
-+    void                FindExtSheet( sal_uInt16 nFileId, sal_uInt16& rnExtSheet, 
-+                                      sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
-+                                      sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab, 
++    void                FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                      sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
 +                                      XclExpRefLogEntry* pRefLogEntry = NULL );
 +
      /** Stores the cell with the given address in a CRN record list. */
@@ -4226,7 +4925,7 @@
      /** Finds or inserts an EXTERNNAME record for an add-in function name.
          @param rnExtSheet  (out-param) Returns the index of the EXTSHEET structure for the add-in function name.
          @param rnExtName  (out-param) Returns the 1-based EXTERNNAME record index.
-@@ -193,6 +202,10 @@ public:
+@@ -193,6 +201,10 @@ public:
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem );
  
@@ -4238,10 +4937,56 @@
      virtual void        Save( XclExpStream& rStrm );
  
 diff --git sc/source/filter/inc/xilink.hxx sc/source/filter/inc/xilink.hxx
-index 0d547fe..c9d7567 100644
+index 0d547fe..ffb9f4c 100644
 --- sc/source/filter/inc/xilink.hxx
 +++ sc/source/filter/inc/xilink.hxx
-@@ -179,6 +179,11 @@ public:
+@@ -107,6 +107,8 @@ enum XclImpExtNameType
+ // ----------------------------------------------------------------------------
+ 
+ class XclImpCachedMatrix;
++class ScTokenArray;
++class XclImpSupbook;
+ 
+ /** Stores contents of an external name.
+     @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */
+@@ -114,21 +116,26 @@ class XclImpExtName
+ {
+ public:
+     /** Reads the external name from the stream. */
+-    explicit            XclImpExtName( XclImpStream& rStrm, bool bAddIn = false );
++    explicit            XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn = false, 
++                                       ExcelToSc* pFormulaConv = NULL );
+                         ~XclImpExtName();
+ 
+     /** Create and apply the cached list of this DDE Link to the document. */
+     void                CreateDdeData( ScDocument& rDoc,
+                             const String& rApplc, const String& rExtDoc ) const;
+ 
++    void                CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const;
++
+     inline XclImpExtNameType GetType() const { return meType; }
+     inline const String& GetName() const { return maName; }
+     inline sal_uInt32   GetStorageId() const { return mnStorageId; }
+ 
+ private:
+     typedef ::std::auto_ptr< XclImpCachedMatrix > XclImpCachedMatrixPtr;
++    typedef ::std::auto_ptr< ScTokenArray >       TokenArrayPtr;
+ 
+     XclImpCachedMatrixPtr mxDdeMatrix;      /// Cached results of the DDE link.
++    TokenArrayPtr       mxArray;            /// Formula tokens for external name.
+     String              maName;             /// The name of the external name.
+     sal_uInt32          mnStorageId;        /// Storage ID for OLE object storages.
+     XclImpExtNameType   meType;             /// Type of the external name.
+@@ -168,7 +175,7 @@ public:
+     /** Reads a CRN record and appends it to the current SUPBOOK. */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns true, if the specified XTI entry contains an internal reference. */
+     bool                IsSelfRef( sal_uInt16 nXtiIndex ) const;
+@@ -179,6 +186,11 @@ public:
                              sal_uInt16 nXtiIndex ) const;
      /** Returns the specified external name or 0 on error. */
      const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
@@ -4253,7 +4998,7 @@
      /** Tries to decode the URL of the specified XTI entry to OLE or DDE link components.
          @descr  For DDE links: Decodes to application name and topic.
          For OLE object links: Decodes to class name and document URL.
-@@ -186,10 +191,12 @@ public:
+@@ -186,10 +198,12 @@ public:
      bool                GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const;
      /** Returns the specified macro name or an empty string on error. */
      const String&       GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
@@ -4291,12 +5036,24 @@
  	return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab );
  }
  
+diff --git sc/source/ui/docshell/docsh.cxx sc/source/ui/docshell/docsh.cxx
+index c702954..219b227 100644
+--- sc/source/ui/docshell/docsh.cxx
++++ sc/source/ui/docshell/docsh.cxx
+@@ -2093,6 +2093,7 @@ bool lcl_NeedHashRegen(const ScDocument& rDoc, ScPasswordHash eHash)
+ 
+ BOOL __EXPORT ScDocShell::ConvertTo( SfxMedium &rMed )
+ {
++    fprintf(stdout, "ScDocShell::ConvertTo:   ****************************************\n");
+ 	RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ConvertTo" );
+ 
+ 	ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() );
 diff --git sc/source/ui/docshell/externalrefmgr.cxx sc/source/ui/docshell/externalrefmgr.cxx
 new file mode 100644
-index 0000000..b1d4117
+index 0000000..7e3ddcc
 --- /dev/null
 +++ sc/source/ui/docshell/externalrefmgr.cxx
-@@ -0,0 +1,1115 @@
+@@ -0,0 +1,1332 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -4399,6 +5156,67 @@
 +
 +// ============================================================================
 +
++ScExternalRefCache::Table::Table()
++{
++}
++
++ScExternalRefCache::Table::~Table()
++{
++}
++
++void ScExternalRefCache::Table::setCell(SCROW nRow, SCCOL nCol, TokenRef pToken)
++{
++    StackPrinter __stack_print__("ScExternalRefCache:Table::setCell");
++    fprintf(stdout, "ScExternalRefCache:Table::setCell:   row = %d; col = %d\n", nRow, nCol);
++    using ::std::pair;
++    RowsDataType::iterator itrRow = maRows.find(nRow);
++    if (itrRow == maRows.end())
++    {
++        // This row does not exist yet.
++        pair<RowsDataType::iterator, bool> res = maRows.insert(
++            RowsDataType::value_type(nRow, RowDataType()));
++
++        if (!res.second)
++            return;
++
++        itrRow = res.first;
++    }
++
++    // Insert this token into the specified column location.  I don't need to 
++    // check for existing data.  Just overwrite it.
++    RowDataType& rRow = itrRow->second;
++    rRow.insert(RowDataType::value_type(nCol, pToken));
++    fprintf(stdout, "ScExternalRefCache:Table::setCell:   token inserted (row = %d; col = %d)\n", nRow, nCol);
++}
++
++ScToken* ScExternalRefCache::Table::getCell(SCROW nRow, SCCOL nCol) const
++{
++    StackPrinter __stack_print__("ScExternalRefCache:Table::getCell");
++    fprintf(stdout, "ScExternalRefCache:Table::getCell:   row = %d; col = %d\n", nRow, nCol);
++
++    RowsDataType::const_iterator itrTable = maRows.find(nRow);
++    if (itrTable == maRows.end())
++    {
++        fprintf(stdout, "ScExternalRefCache:Table::getCell:   row not found\n");
++        // this table doesn't have the specified row.
++        return NULL;
++    }
++
++    const RowDataType& rRowData = itrTable->second;
++    RowDataType::const_iterator itrRow = rRowData.find(nCol);
++    if (itrRow == rRowData.end())
++    {
++        fprintf(stdout, "ScExternalRefCache:Table::getCell:   column not found\n");
++        // this row doesn't have the specified column.
++        return NULL;
++    }
++
++    fprintf(stdout, "ScExternalRefCache:Table::getCell:   cached cell found\n");
++    return itrRow->second.get();
++}
++
++// ----------------------------------------------------------------------------
++
 +ScExternalRefCache::ScExternalRefCache()
 +{
 +}
@@ -4410,30 +5228,31 @@
 +{
 +    StackPrinter __stack_print__("ScExternalRefCache::getCellData");
 +
-+    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
 +    if (itrDoc == maDocs.end())
++    {
++        fprintf(stdout, "ScExternalRefCache::getCellData:   specified document not cached\n");
 +        // specified document is not cached.
 +        return NULL;
++    }
 +
-+    DocItem& rDoc = itrDoc->second;
-+    TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
++    const DocItem& rDoc = itrDoc->second;
++    TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
 +    if (itrTabId == rDoc.maTableNameIndex.end())
++    {
++        fprintf(stdout, "ScExternalRefCache::getCellData:   table not in cache\n");
 +        // the specified table is not in cache.
 +        return NULL;
++    }
 +
-+    TableDataTypeRef pTableData = rDoc.maTables[itrTabId->second];
-+    TableDataType::iterator itrTable = pTableData->find(nRow);
-+    if (itrTable == pTableData->end())
-+        // this table doesn't have the specified row.
-+        return NULL;
-+
-+    RowDataType& rRowData = itrTable->second;
-+    RowDataType::iterator itrRow = rRowData.find(nCol);
-+    if (itrRow == rRowData.end())
-+        // this row doesn't have the specified column.
++    const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
++    if (!pTableData.get())
++    {
++        fprintf(stdout, "ScExternalRefCache::getCellData:   table instance is NULL\n");
++        // the table data is not instantiated yet.
 +        return NULL;
-+
-+    return itrRow->second.get();
++    }
++    return pTableData->getCell(nRow, nCol);
 +}
 +
 +ScTokenArray* ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
@@ -4446,6 +5265,13 @@
 +        return NULL;
 +
 +    DocItem& rDoc = itrDoc->second;
++    RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange);
++    if (itrRange != rDoc.maRangeArrays.end())
++    {
++        fprintf(stdout, "ScExternalRefCache::getCellRangeData:   range array cached.  let's use this.\n");
++        return itrRange->second.get();
++    }
++
 +    TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
 +    if (itrTabId == rDoc.maTableNameIndex.end())
 +        // the specified table is not in cache.
@@ -4465,33 +5291,25 @@
 +        // not all tables are cached.
 +        return NULL;
 +
-+    auto_ptr<ScTokenArray> pArray(new ScTokenArray);
++    TokenArrayRef pArray(new ScTokenArray);
 +    bool bFirstTab = true;
 +    for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
 +    {
-+        TableDataTypeRef pTab = rDoc.maTables[nTab];
++        TableTypeRef pTab = rDoc.maTables[nTab];
++        if (!pTab.get())
++            return NULL;
 +
 +        ScMatrixRef xMat = new ScMatrix(
 +            static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
 +
-+
 +        for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
 +        {
-+            TableDataType::iterator itrTable = pTab->find(nRow);
-+            if (itrTable == pTab->end())
-+                // this table doesn't have the specified row.
-+                return NULL;
-+
-+            RowDataType& rRowData = itrTable->second;
-+
 +            for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
 +            {
-+                RowDataType::iterator itrRow = rRowData.find(nCol);
-+                if (itrRow == rRowData.end())
-+                    // this row doesn't have the specified column.
++                ScToken* pToken = pTab->getCell(nRow, nCol);
++                if (!pToken)
 +                    return NULL;
 +
-+                ScToken* pToken = itrRow->second.get();
 +                SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
 +                switch (pToken->GetType())
 +                {
@@ -4506,6 +5324,7 @@
 +                }
 +            }
 +        }
++
 +        if (!bFirstTab)
 +            pArray->AddOpCode(ocSep);
 +
@@ -4515,69 +5334,292 @@
 +
 +        bFirstTab = false;
 +    }
-+    return pArray.release();
++    rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
++    return pArray.get();
++}
++
++ScTokenArray* ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::getRangeNameTokens");
++
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    RangeNameMap& rMap = pDoc->maRangeNames;
++    RangeNameMap::const_iterator itr = rMap.find(rName);
++    if (itr == rMap.end())
++        return NULL;
++
++    return itr->second.get();
++}
++
++void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::setRangeNameTokens");
++
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return;
++
++    RangeNameMap& rMap = pDoc->maRangeNames;
++    rMap.insert(RangeNameMap::value_type(rName, pArray));
++    fprintf(stdout, "ScExternalRefCache::setRangeNameTokens:   name inserted into cache\n");
 +}
 +
 +void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken)
 +{
 +    StackPrinter __stack_print__("ScExternalRefCache::setCellData");
++    if (!isDocInitialized(nFileId))
++        return;
 +
 +    using ::std::pair;
-+    DocDataType::iterator itrDoc = maDocs.find(nFileId);
-+    if (itrDoc == maDocs.end())
-+    {
-+        // specified document is not cached.
-+        pair<DocDataType::iterator, bool> res = maDocs.insert(
-+                DocDataType::value_type(nFileId, DocItem()));
-+
-+        if (!res.second)
-+            // insertion failed.
-+            return;
-+
-+        itrDoc = res.first;
-+    }
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem)
++        return;
 +
-+    DocItem& rDoc = itrDoc->second;
++    DocItem& rDoc = *pDocItem;
 +    
 +    // See if the table by this name already exists.
 +    TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(rTabName);
 +    if (itrTabName == rDoc.maTableNameIndex.end())
++        // Table not found.  Maybe the table name or the file id is wrong ???
++        return;
++
++    TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
++    if (!pTableData.get())
++        pTableData.reset(new Table);
++
++    pTableData->setCell(nRow, nCol, pToken);
++}
++
++void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
++                                          TokenArrayRef pArray)
++{
++    using ::std::pair;
++    StackPrinter __stack_print__("ScExternalRefCache::setCellRangeData");
++    if (rData.empty() || !isDocInitialized(nFileId))
++        // nothing to cache
++        return;
++
 +    {
-+        // Insert a new table by this name.
-+        rDoc.maTables.push_back(TableDataTypeRef(new TableDataType));
-+        pair<TableNameIndexMap::iterator, bool> res = rDoc.maTableNameIndex.insert(
-+            TableNameIndexMap::value_type(rTabName, rDoc.maTables.size()-1));
++        vector<SingleRangeData>::const_iterator itr = rData.begin(), itrEnd = rData.end();
++        for (; itr != itrEnd; ++itr)
++        {
++            fprintf(stdout, "ScExternalRefCache::setCellRangeData:   tab name to cache = '%s'\n", 
++                    rtl::OUStringToOString(itr->maTableName, RTL_TEXTENCODING_UTF8).getStr());
++        }
++    }
 +
-+        if (!res.second)
-+            return;
++    String aStr;
++    rRange.Format(aStr, SCR_ABS_3D, NULL);
++    fprintf(stdout, "ScExternalRefCache::setCellRangeData:   range = '%s'\n", 
++            rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
++
++    // First, get the document item for the given file ID.
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem)
++        return;
++
++    DocItem& rDoc = *pDocItem;
++
++    // Now, find the table position of the first table to cache.
++    const String& rFirstTabName = rData.front().maTableName;
++    TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(rFirstTabName);
++    if (itrTabName == rDoc.maTableNameIndex.end())
++    {
++        // table index not found.
++        fprintf(stdout, "ScExternalRefCache::setCellRangeData:   table index not found\n");
++        return;
++    }
++
++    fprintf(stdout, "ScExternalRefCache::setCellRangeData:   table index for cached table '%s' = %d\n",
++            rtl::OUStringToOString(rFirstTabName, RTL_TEXTENCODING_UTF8).getStr(), itrTabName->second);
++
++    size_t nTab1 = itrTabName->second;
++    SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
++    SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
++    vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
++    for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
++    {
++        size_t i = nTab1 + ::std::distance(itrDataBeg, itrData);
++        TableTypeRef& pTabData = rDoc.maTables[i];
++        if (!pTabData.get())
++            pTabData.reset(new Table);
++
++        for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
++        {
++            for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
++            {
++                SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
++                TokenRef pToken;
++                const ScMatrixRef& pMat = itrData->mpRangeData;
++                if (pMat->IsValue(nC, nR))
++                    pToken.reset(new ScDoubleToken(pMat->GetDouble(nC, nR)));
++                else if (pMat->IsString(nC, nR))
++                    pToken.reset(new ScStringToken(pMat->GetString(nC, nR)));
++                else
++                    pToken.reset(new ScEmptyCellToken(false, false));
 +
-+        itrTabName = res.first;
++                pTabData->setCell(nRow, nCol, pToken);
++            }
++        }
 +    }
 +
-+    TableDataTypeRef pTableData = rDoc.maTables[itrTabName->second];
-+    TableDataType::iterator itrRow = pTableData->find(nRow);
-+    if (itrRow == pTableData->end())
++    rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
++}
++
++bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return false;
++
++    return pDoc->mbInitFromSource;
++}
++
++static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
++{
++    ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
++    if (itr == rMap.end())
++        return false;
++
++    rIndex = itr->second;
++    return true;
++}
++
++void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::initializeDoc");
++
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return;
++
++    size_t n = rTabNames.size();
++    for (size_t i = 0; i < n; ++i)
++        fprintf(stdout, "ScExternalRefCache::initializeDoc:   %d: '%s'\n", i, rtl::OUStringToOString(rTabNames[i], RTL_TEXTENCODING_UTF8).getStr());
++
++    // table name list - the list must include all table names in the source 
++    // document and only to be populated when loading the source document, not
++    // when loading cached data from, say, Excel XCT/CRN records.
++    pDoc->maTableNames.assign(rTabNames.begin(), rTabNames.end());
++    
++    // data tables - preserve any existing data that may have been set during 
++    // Excel import.
++    vector<TableTypeRef> aNewTables(n);
++    for (size_t i = 0; i < n; ++i)
 +    {
-+        // This row does not exist yet.
-+        pair<TableDataType::iterator, bool> res = pTableData->insert(
-+            TableDataType::value_type(nRow, RowDataType()));
++        size_t nIndex;
++        if (lcl_getTableDataIndex(pDoc->maTableNameIndex, rTabNames[i], nIndex))
++        {
++            fprintf(stdout, "ScExternalRefCache::initializeDoc:   transferring '%s'\n", rtl::OUStringToOString(rTabNames[i], RTL_TEXTENCODING_UTF8).getStr());
++            aNewTables[i] = pDoc->maTables[nIndex];
++        }
++    }
++    pDoc->maTables.swap(aNewTables);
 +
-+        if (!res.second)
-+            return;
++    // name index map
++    TableNameIndexMap aNewNameIndex;
++    for (size_t i = 0; i < n; ++i)
++        aNewNameIndex.insert(TableNameIndexMap::value_type(rTabNames[i], i));
++    pDoc->maTableNameIndex.swap(aNewNameIndex);
 +
-+        itrRow = res.first;
++    pDoc->mbInitFromSource = true;
++}
++#if 0
++const String* ScExternalRefCache::getExternalTableName(sal_uInt16 nFileId, SCTAB nTab)
++{
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem || nTab < 0)
++        return NULL;
++
++    const vector<String>& rNames = pDocItem->maTableNames;
++    if (static_cast<size_t>(nTab) >= rNames.size())
++        return NULL;
++
++    return &rNames[nTab];
++}
++
++SCTAB ScExternalRefCache::getExternalTableId(sal_uInt16 nFileId, const String& rTabName)
++{
++    if (!isDocInitialized(nFileId))
++        return -1;
++
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem)
++        return -1;
++
++    TableNameIndexMap::const_iterator itr = pDocItem->maTableNameIndex.find(rTabName);
++    if (itr == pDocItem->maTableNameIndex.end())
++        return -1;
++
++    return static_cast<SCTAB>(itr->second);
++}
++#endif
++const vector<String>* ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId) const
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    return &pDoc->maTableNames;
++}
++
++ScExternalRefCache::Table* ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::getCacheTable");
++
++    fprintf(stdout, "ScExternalRefCache::getCacheTable:   tab name requested = '%s'\n", 
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    DocItem& rDoc = *pDoc;
++
++    size_t nIndex;
++    if (lcl_getTableDataIndex(rDoc.maTableNameIndex, rTabName, nIndex))
++    {
++        fprintf(stdout, "ScExternalRefCache::getCacheTable:   exists\n");
++        return rDoc.maTables[nIndex].get();
 +    }
 +
-+    // Insert this token into the specified column location.  I don't need to 
-+    // check for existing data.  Just overwrite it.
-+    RowDataType& rRow = itrRow->second;
-+    rRow.insert(RowDataType::value_type(nCol, pToken));
-+    fprintf(stdout, "ScExternalRefCache::setCellData:   token inserted\n");
++    fprintf(stdout, "ScExternalRefCache::getCacheTable:   creating a new cache table\n");
++
++    // Specified table doesn't exist yet.  Create one.
++    TableTypeRef pTab(new Table);
++    rDoc.maTables.push_back(pTab);
++    rDoc.maTableNames.push_back(rTabName);
++    rDoc.maTableNameIndex.insert(
++        TableNameIndexMap::value_type(rTabName, rDoc.maTables.size()-1));
++    return pTab.get();
 +}
 +
-+void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange,
-+                                          const vector<MatrixRef>& rData)
++void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
 +{
++    maDocs.erase(nFileId);
++}
++
++ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
++{
++    using ::std::pair;
++    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++    {
++        // specified document is not cached.
++        pair<DocDataType::iterator, bool> res = maDocs.insert(
++                DocDataType::value_type(nFileId, DocItem()));
++
++        if (!res.second)
++            // insertion failed.
++            return NULL;
++
++        itrDoc = res.first;
++    }
++
++    return &itrDoc->second;
 +}
 +
 +// ============================================================================
@@ -4645,8 +5687,6 @@
 +
 +static ScToken* lcl_convertToToken(ScBaseCell* pCell)
 +{
-+    StackPrinter __stack_print__("::lcl_convertToToken");
-+
 +    if (!pCell)
 +        return NULL;
 +
@@ -4695,7 +5735,8 @@
 +    return NULL;
 +}
 +
-+static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange)
++static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange, 
++                                             vector<ScExternalRefCache::SingleRangeData>& rCacheData)
 +{
 +    const ScAddress& s = rRange.aStart;
 +    const ScAddress& e = rRange.aEnd;
@@ -4706,7 +5747,9 @@
 +
 +    auto_ptr<ScTokenArray> pArray(new ScTokenArray);
 +    bool bFirstTab = true;
-+    for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
++    vector<ScExternalRefCache::SingleRangeData>::iterator 
++        itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
++    for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
 +    {
 +        ScMatrixRef xMat = new ScMatrix(
 +            static_cast<SCSIZE>(nCol2-nCol1+1),
@@ -4769,6 +5812,8 @@
 +        ScMatrixToken aToken(pMat2);
 +        pArray->AddToken(aToken);
 +
++        itrCache->mpRangeData = xMat;
++
 +        bFirstTab = false;
 +    }
 +    return pArray.release();
@@ -4786,6 +5831,24 @@
 +    clear();
 +}
 +
++ScExternalRefCache::Table* ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName)
++{
++    return maRefCache.getCacheTable(nFileId, rTabName);
++}
++
++void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
++{
++    StackPrinter __stack_print__("ScExternalRefManager::storeRangeNameTokens");
++    ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
++    maRefCache.setRangeNameTokens(nFileId, rName, pArray);
++
++    for (ScToken* pToken = pArray->First(); pToken; pToken = pArray->Next())
++    {
++        fprintf(stdout, "ScExternalRefManager::storeRangeNameTokens:   type = %d; opcode = %d\n", 
++                pToken->GetType(), pToken->GetOpCode());
++    }
++}
++
 +ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
 +                                                 const ScAddress* pCurPos, SCTAB* pTab)
 +{
@@ -4843,129 +5906,81 @@
 +    return pTok.get();
 +}
 +
-+#if 1
-+ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress* pCurPos)
++ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
 +{
 +    if (pCurPos)
 +        insertReferencingCell(nFileId, *pCurPos);
-+    return getSingleRefToken(nFileId, rCell);
-+}
 +
-+ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell)
-+{
++    // Check if the given table name and the cell position is cached.
++    ScTokenArray* p = maRefCache.getCellRangeData(nFileId, rTabName, rRange);
++    if (p)
 +    {
-+        String aStr;
-+        rCell.Format(aStr, SCA_ABS_3D);
-+        const String *pFile = getExternalFileName(nFileId);
-+        fprintf(stdout, "ScExternalRefManager::getSingleRefToken: --begin (file = '%s'; address = '%s')\n",
-+                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr(),
-+                rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
++        fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   range reference cached.\n");
++        return p;
 +    }
 +
-+    SingleTokenMap& rMap = getDocumentCache(nFileId)->maSingleTokens;
-+    SingleTokenMap::iterator itr = rMap.find(rCell);
-+    if (itr != rMap.end())
-+    {
-+        fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   reference cached\n");
-+        // this single reference is cached.
-+        return itr->second.get();
-+    }
++    fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   range reference not cached.\n");
 +
-+    // reference not cached.  read from the source document.
 +    ScDocument* pSrcDoc = getSrcDocument(nFileId);
 +    if (!pSrcDoc)
-+        return NULL;
-+
-+    ScBaseCell* pCell = NULL;
-+    pSrcDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
-+    TokenRef pTok(lcl_convertToToken(pCell));
-+
-+    if (!pTok.get())
 +    {
-+        // Cell in the source document is probably empty.
-+        pTok.reset(new ScEmptyCellToken(false, false));
++        fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   source document is null\n");
++        return NULL;
 +    }
 +
-+    rMap.insert(SingleTokenMap::value_type(rCell, pTok));
-+    fprintf(stdout, "ScExternalRefManager::getSingleRefToken: --end\n");
-+    return pTok.get();
-+}
-+#endif
-+
-+ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
-+{
-+    if (pCurPos)
-+        insertReferencingCell(nFileId, *pCurPos);
-+
-+    // Check if the given table name and the cell position is cached.
-+    auto_ptr<ScTokenArray> pArray;
-+    pArray.reset(maRefCache.getCellRangeData(nFileId, rTabName, rRange));
-+    if (pArray.get())
++    SCTAB nTab1;
++    if (!pSrcDoc->GetTable(rTabName, nTab1))
 +    {
-+        fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   range reference cached.\n");
-+        return pArray.release();
++        // specified table name doesn't exist in the source document.
++        fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   tab name doesn't exist in the source document.\n");
++        return NULL;
 +    }
 +
++    fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   tab id = %d\n", nTab1);
 +
-+    SCTAB nTab = getExternalTableId(nFileId, rTabName);
-+    if (nTab < 0)
-+        return NULL;
-+    
 +    ScRange aRange(rRange);
 +    SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
-+    aRange.aStart.SetTab(nTab);
-+    aRange.aEnd.SetTab(nTab + nTabSpan);
-+    return getDoubleRefTokens(nFileId, aRange);
-+}
 +
-+#if 1
-+ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange)
-+{
-+    {
-+        String aStr;
-+        rRange.Format(aStr, SCR_ABS_3D, mpDoc);
-+        const String *pFile = getExternalFileName(nFileId);
-+        fprintf(stdout, "ScExternalRefManager::getDoubleRefToken: --begin (file = '%s'; range = '%s)\n",
-+                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr(), 
-+                rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
-+    }
++    vector<ScExternalRefCache::SingleRangeData> aCacheData;
++    aCacheData.reserve(nTabSpan+1);
++    aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++    aCacheData.back().maTableName = rTabName;
 +
-+    DoubleTokenMap& rMap = getDocumentCache(nFileId)->maDoubleTokens;
-+    DoubleTokenMap::iterator itr = rMap.find(rRange);
-+    if (itr != rMap.end())
++    for (SCTAB i = 1; i < nTabSpan + 1; ++i)
 +    {
-+        fprintf(stdout, "ScExternalRefManager::getDoubleRefToken:   range reference cached\n");
-+        // this range reference is cached.
-+        return itr->second.get();
++        String aTabName;
++        if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
++        {
++            fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   src doc does not have a table named '%s'\n",
++                    rtl::OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr());
++            break;
++        }
++
++        aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++        aCacheData.back().maTableName = aTabName;
 +    }
 +
-+    // reference not cached.  read from the source document.
-+    ScDocument* pSrcDoc = getSrcDocument(nFileId);
-+    if (!pSrcDoc)
-+        return NULL;
++    aRange.aStart.SetTab(nTab1);
++    aRange.aEnd.SetTab(nTab1 + nTabSpan);
 +
-+    TokenArrayRef pArray(lcl_convertToTokenArray(pSrcDoc, rRange));
-+    if (!pArray.get())
-+    {
-+        // highly unlikely since lcl_convertToTokenArray never returns NULL.
-+        fprintf(stdout, "ScExternalRefManager::getDoubleRefToken: --end (NULL)\n");
-+        return NULL;
-+    }
++    ScExternalRefCache::TokenArrayRef pArray;
++    pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
++
++    // Cache these values.
++    maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray);
 +
-+    rMap.insert(DoubleTokenMap::value_type(rRange, pArray));
-+    fprintf(stdout, "ScExternalRefManager::getDoubleRefToken: --end\n");
 +    return pArray.get();
 +}
-+#endif
 +
 +ScTokenArray* ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
 +{
++    StackPrinter __stack_print__("ScExternalRefManager::getRangeNameTokens");
 +    if (pCurPos)
 +    {
 +        String aCellStr;
 +        pCurPos->Format(aCellStr, SCA_ABS_3D);
 +        const String* pFile = getExternalFileName(nFileId);
-+        fprintf(stdout, "ScExternalRefManager::getRangeNameTokens: --begin (file = '%s' [%d]; name = '%s'; pos = '%s')\n",
++        fprintf(stdout, "ScExternalRefManager::getRangeNameTokens:   file = '%s' [%d]; name = '%s'; pos = '%s'\n",
 +                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr(),
 +                nFileId,
 +                rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8).getStr(),
@@ -4975,14 +5990,11 @@
 +    if (pCurPos)
 +        insertReferencingCell(nFileId, *pCurPos);
 +
-+    // First, check if this name has already been cached.
-+    RangeNameMap& rMap = getDocumentCache(nFileId)->maRangeNames;
-+    RangeNameMap::iterator itr = rMap.find(rName);
-+    if (itr != rMap.end())
++    ScTokenArray* pArray = maRefCache.getRangeNameTokens(nFileId, rName);
++    if (pArray)
 +    {
 +        fprintf(stdout, "ScExternalRefManager::getRangeNameTokens:   name is cached\n");
-+        // this name is cached.
-+        return itr->second.get();
++        return pArray;
 +    }
 +
 +    ScDocument* pSrcDoc = getSrcDocument(nFileId);
@@ -5015,16 +6027,20 @@
 +        {
 +            case svSingleRef:
 +            {
-+                fprintf(stdout, "ScDocument::FindExternalRangeName:   single ref\n");
-+                ScExternalSingleRefToken aNewToken(nFileId, String(), pToken->GetSingleRef());
++                const SingleRefData& rRef = pToken->GetSingleRef();
++                String aTabName;
++                pSrcDoc->GetName(rRef.nTab, aTabName);
++                ScExternalSingleRefToken aNewToken(nFileId, aTabName, pToken->GetSingleRef());
 +                pNew->AddToken(aNewToken);
 +                bTokenAdded = true;
 +            }
 +            break;
 +            case svDoubleRef:
 +            {
-+                fprintf(stdout, "ScDocument::FindExternalRangeName:   double ref\n");
-+                ScExternalDoubleRefToken aNewToken(nFileId, String(), pToken->GetDoubleRef());
++                const SingleRefData& rRef = pToken->GetSingleRef();
++                String aTabName;
++                pSrcDoc->GetName(rRef.nTab, aTabName);
++                ScExternalDoubleRefToken aNewToken(nFileId, aTabName, pToken->GetDoubleRef());
 +                pNew->AddToken(aNewToken);
 +                bTokenAdded = true;
 +            }
@@ -5035,8 +6051,7 @@
 +            pNew->AddToken(*pToken);
 +    }
 +
-+    rMap.insert(RangeNameMap::value_type(rName, pNew));
-+    fprintf(stdout, "ScExternalRefManager::getRangeNameTokens: --end\n");
++    maRefCache.setRangeNameTokens(nFileId, rName, pNew);
 +    return pNew.get();
 +}
 +
@@ -5091,18 +6106,6 @@
 +    maRefCells.insert(RefCellMap::value_type(nFileId, aSet));
 +}
 +
-+ScExternalRefManager::DocCache* ScExternalRefManager::getDocumentCache(
-+    sal_uInt16 nFileId)
-+{
-+    DocCacheMap::iterator itr = maCachedDocContents.find(nFileId);
-+    if (itr != maCachedDocContents.end())
-+        return itr->second.get();
-+
-+    DocCacheRef pCache(new DocCache);
-+    maCachedDocContents.insert(DocCacheMap::value_type(nFileId, pCache));
-+    return pCache.get();
-+}
-+
 +ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
 +{
 +    DocShellMap::iterator itrEnd = maDocShells.end();
@@ -5122,9 +6125,11 @@
 +        return NULL;
 +    }
 +
-+    fprintf(stdout, "ScExternalRefManager::getSourceDocument:   file not found: '%s'\n",
++    fprintf(stdout, "ScExternalRefManager::getSourceDocument:   file not loaded yet: '%s'\n",
 +            rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr());
 +
++    // TODO: Check whether the file really exists.  If not, return NULL.
++
 +    String aFilter;
 +    SrcDoc aSrcDoc;
 +    aSrcDoc.maShell = loadSrcDocument(*pFile, aFilter);
@@ -5144,19 +6149,20 @@
 +    SfxObjectShell* p = aSrcDoc.maShell;
 +    ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
 +
-+    // Store all its table names.  Excel exporter needs this info.
-+    vector<String> aTableNames;
-+    SCTAB nCount = pSrcDoc->GetTableCount();
-+    aTableNames.reserve(nCount);
-+    for (SCTAB i = 0; i < nCount; ++i)
++    SCTAB nTabCount = pSrcDoc->GetTableCount();
++    if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
 +    {
-+        String aTabName;
-+        pSrcDoc->GetName(i, aTabName);
-+        aTableNames.push_back(aTabName);
++        // Populate the cache with all table names in the source document.
++        vector<String> aTabNames;
++        aTabNames.reserve(nTabCount);
++        for (SCTAB i = 0; i < nTabCount; ++i)
++        {
++            String aName;
++            pSrcDoc->GetName(i, aName);
++            aTabNames.push_back(aName);
++        }
++        maRefCache.initializeDoc(nFileId, aTabNames);
 +    }
-+    DocCache* pCache = getDocumentCache(nFileId);
-+    pCache->maTableNames.swap(aTableNames);
-+
 +    return pSrcDoc;
 +}
 +
@@ -5284,41 +6290,9 @@
 +    return &maFileNames[nFileId];
 +}
 +
-+const String* ScExternalRefManager::getExternalTableName(sal_uInt16 nFileId, SCTAB nTabId)
-+{
-+    if (nFileId >= maFileNames.size())
-+        return NULL;
-+
-+    DocCache* pCache = getDocumentCache(nFileId);
-+    if (nTabId >= pCache->maTableNames.size())
-+        return NULL;
-+
-+    return &pCache->maTableNames[nTabId];
-+}
-+
-+SCTAB ScExternalRefManager::getExternalTableId(sal_uInt16 nFileId, const String& rTabName)
++const vector<String>* ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId) const
 +{
-+    vector<String>& rNames = getDocumentCache(nFileId)->maTableNames;
-+    vector<String>::iterator itrBeg = rNames.begin(), itrEnd = rNames.end();
-+    vector<String>::iterator itr = find(itrBeg, itrEnd, rTabName);
-+    if (itr != itrEnd)
-+        // found in cache
-+        return static_cast<SCTAB>(distance(itrBeg, itr));
-+
-+    // Loading the source document resets the table name vector.
-+    ScDocument* pSrcDoc = getSrcDocument(nFileId);
-+    if (!pSrcDoc)
-+        // source document could not be loaded.
-+        return -1;
-+
-+    itrBeg = rNames.begin();
-+    itrEnd = rNames.end();
-+    itr = find(itrBeg, itrEnd, rTabName);
-+    if (itr != itrEnd)
-+        // found in the source document
-+        return static_cast<SCTAB>(distance(itrBeg, itr));
-+
-+    return -1;
++    return maRefCache.getAllTableNames(nFileId);
 +}
 +
 +template<typename MapContainer>
@@ -5360,7 +6334,7 @@
 +                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr());
 +    }
 +
-+    lcl_removeByFileId(nFileId, maCachedDocContents);
++    maRefCache.clearCache(nFileId);
 +    lcl_removeByFileId(nFileId, maDocShells);
 +
 +    if (bBreakLink)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]