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



Author: kyoshida
Date: Tue Jul 29 14:21:14 2008
New Revision: 13428
URL: http://svn.gnome.org/viewvc/ooo-build?rev=13428&view=rev

Log:
2008-07-29  Kohei Yoshida  <kyoshida novell com>

	* patches/test/calc-external-defined-names.diff: worked on using the 
	new external ref manager code for the existing cell and cell range 
	references.  Still a long road ahead but the end is approaching...
	hopefully.


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	Tue Jul 29 14:21:14 2008
@@ -1,3 +1,44 @@
+diff --git sc/inc/address.hxx sc/inc/address.hxx
+index f92fc8e..f15a341 100644
+--- sc/inc/address.hxx
++++ sc/inc/address.hxx
+@@ -287,6 +287,15 @@ public:
+     };
+     static const Details detailsOOOa1;
+ 
++    struct ExternalInfo
++    {
++        String      maTabName;
++        sal_uInt16  mnFileId;
++        bool        mbExternal;
++
++        inline ExternalInfo() : mnFileId(0), mbExternal(false) {}
++    };
++
+     inline ScAddress() : nRow(0), nCol(0), nTab(0) {}
+     inline ScAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP )
+         : nRow(nRowP), nCol(nColP), nTab(nTabP)
+@@ -317,8 +326,8 @@ public:
+     inline void GetVars( SCCOL& nColP, SCROW& nRowP, SCTAB& nTabP ) const
+     { nColP = nCol; nRowP = nRow; nTabP = nTab; }
+ 
+-    USHORT Parse( const String&, ScDocument* = NULL,
+-                  const Details& rDetails = detailsOOOa1);
++    USHORT Parse( const String&, ScDocument* = NULL, 
++                  const Details& rDetails = detailsOOOa1, ExternalInfo* pExtInfo = NULL);
+     void Format( String&, USHORT = 0, ScDocument* = NULL,
+                  const Details& rDetails = detailsOOOa1) const;
+ 
+@@ -463,7 +472,8 @@ public:
+     inline bool In( const ScRange& ) const;     // is Range& in Range?
+ 
+     USHORT Parse( const String&, ScDocument* = NULL,
+-                  const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 );
++                  const ScAddress::Details& rDetails = ScAddress::detailsOOOa1,
++                  ScAddress::ExternalInfo* pExtInfo = NULL );
+     USHORT ParseAny( const String&, ScDocument* = NULL,
+                      const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 );
+     USHORT ParseCols( const String&, ScDocument* = NULL,
 diff --git sc/inc/compiler.hrc sc/inc/compiler.hrc
 index 92b7e82..22d77cb 100644
 --- sc/inc/compiler.hrc
@@ -49,7 +90,7 @@
  /*** error constants #... ***/
  #define SC_OPCODE_START_ERRORS       30
 diff --git sc/inc/compiler.hxx sc/inc/compiler.hxx
-index 2d816d1..332dd31 100644
+index 2d816d1..74f8f35 100644
 --- sc/inc/compiler.hxx
 +++ sc/inc/compiler.hxx
 @@ -45,6 +45,7 @@
@@ -60,26 +101,41 @@
  
  namespace com { namespace sun { namespace star {
      namespace sheet {
-@@ -151,6 +152,10 @@ public:
+@@ -100,6 +101,7 @@ namespace com { namespace sun { namespace star {
+ class ScDocument;
+ class ScMatrix;
+ class ScRangeData;
++class ScExternalRefManager;
+ 
+ // constants and data types internal to compiler
+ 
+@@ -151,6 +153,15 @@ public:
              bool        bHasForceArray;
          } sbyte;
          ComplRefData aRef;
 +        struct {
++            sal_uInt16      nFileId;
++            sal_Unicode     cTabName[MAXSTRLEN+1];
++            ComplRefData    aRef;
++        } extref;
++        struct {
 +            sal_uInt16  nFileId;
 +            sal_Unicode cName[MAXSTRLEN+1];
 +        } extname;
          ScMatrix*    pMat;
          USHORT       nIndex;                // index into name collection
          sal_Unicode  cStr[ MAXSTRLEN+1 ];   // string (up to 255 characters + 0)
-@@ -180,6 +185,7 @@ public:
+@@ -180,6 +191,9 @@ public:
      void SetDouble( double fVal );
      void SetInt( int nVal );
      void SetName( USHORT n );
++    void SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
++    void SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef );
 +    void SetExternalName( sal_uInt16 nFileId, const String& rName );
      void SetMatrix( ScMatrix* p );
      void SetExternal(const sal_Unicode* pStr);
      // These methods are ok to use, reference count not cleared.
-@@ -228,6 +234,16 @@ public:
+@@ -228,6 +242,28 @@ public:
                                     xub_StrLen nSrcPos,
                                     const CharClass* pCharClass) const = 0;
  
@@ -93,10 +149,22 @@
 +
 +        virtual String makeExternalNameStr( const String& rFile, const String& rName ) const = 0;
 +
++        virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                         sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
++                                         ScExternalRefManager* pRefMgr ) const
++        {
++        }
++
++        virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                         sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                         ScExternalRefManager* pRefMgr ) const
++        {
++        }
++
          enum SpecialSymbolType
          {
              /** 
-@@ -447,6 +463,7 @@ private:
+@@ -447,6 +483,7 @@ private:
      BOOL IsDoubleReference( const String& );
      BOOL IsMacro( const String& );
      BOOL IsNamedRange( const String& );
@@ -135,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..c034a5b
+index 0000000..1245062
 --- /dev/null
 +++ sc/inc/externalrefmgr.hxx
-@@ -0,0 +1,224 @@
+@@ -0,0 +1,288 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -186,11 +254,14 @@
 +
 +class ScDocument;
 +class ScToken;
++class ScMatrix;
 +class ScTokenArray;
 +class String;
 +class SfxObjectShellRef;
 +class Window;
 +
++class ScExternalRefCache;
++
 +class ScExternalRefLink : public ::sfx2::SvBaseLink
 +{
 +public:
@@ -217,6 +288,45 @@
 +
 +// ============================================================================
 +
++/** 
++ * Cache table for external reference data.
++ */
++class ScExternalRefCache
++{
++public:
++    typedef ::boost::shared_ptr<ScToken> TokenRef;
++    typedef ::boost::shared_ptr<ScMatrix> MatrixRef;
++
++    ScExternalRefCache();
++    ~ScExternalRefCache();
++
++    ScToken* getCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol);
++    ScTokenArray* getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange);
++
++    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);
++
++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, size_t, ScStringHashCode>   TableNameIndexMap;
++    
++    struct DocItem
++    {
++        TableListType       maTables;
++        TableNameIndexMap   maTableNameIndex;    
++    };
++    typedef ::std::hash_map<sal_uInt16, DocItem>  DocDataType;
++
++    DocDataType maDocs;
++};
++
++// ============================================================================
++
 +class ScExternalRefManager
 +{
 +private:
@@ -274,8 +384,15 @@
 +    explicit ScExternalRefManager(ScDocument* pDoc);
 +    ~ScExternalRefManager();
 +
++    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
++
++    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 
@@ -300,6 +417,16 @@
 +    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);
 +    
 +    void refreshNames(sal_uInt16 nFileId);
 +    void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile);
@@ -310,7 +437,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);
@@ -333,6 +463,8 @@
 +    void purgeStaleSrcDocument(sal_Int32 nTimeOut);
 +
 +private:
++    ScExternalRefCache maRefCache;
++
 +    ScDocument* mpDoc;
 +
 +    /** 
@@ -376,7 +508,7 @@
  		ocIf				= SC_OPCODE_IF,
  		ocChose				= SC_OPCODE_CHOSE,
 diff --git sc/inc/token.hxx sc/inc/token.hxx
-index ded3a94..a28da1c 100644
+index ded3a94..92a9137 100644
 --- sc/inc/token.hxx
 +++ sc/inc/token.hxx
 @@ -64,7 +64,7 @@ enum StackVarEnum
@@ -388,7 +520,7 @@
      svError,                            // error token
      svMissing = 0x70,                   // 0 or ""
      svSep,                              // separator, ocSep, ocOpen, ocClose
-@@ -448,6 +448,61 @@ public:
+@@ -448,6 +448,65 @@ public:
  };
  
  
@@ -396,15 +528,17 @@
 +{
 +private:
 +    sal_uInt16                  mnFileId;
++    String                      maTabName;
 +    SingleRefData               maSingleRef;
 +
 +                                ScExternalSingleRefToken(); // disabled
 +public:
-+                                ScExternalSingleRefToken( sal_uInt16 nFileId, const SingleRefData& r );
++                                ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& r );
 +                                ScExternalSingleRefToken( const ScExternalSingleRefToken& r );
 +    virtual                     ~ScExternalSingleRefToken();
 +
 +    virtual USHORT                  GetIndex() const;
++    virtual const String&           GetString() const;
 +    virtual const SingleRefData&    GetSingleRef() const;
 +    virtual SingleRefData&          GetSingleRef();
 +    virtual BOOL                    operator==( const ScToken& rToken ) const;
@@ -415,15 +549,17 @@
 +{
 +private:
 +    sal_uInt16                  mnFileId;
-+    ComplRefData               maDoubleRef;
++    String                      maTabName;  // name of the first sheet
++    ComplRefData                maDoubleRef;
 +
 +                                ScExternalDoubleRefToken(); // disabled
 +public:
-+                                ScExternalDoubleRefToken( sal_uInt16 nFileId, const ComplRefData& r );
++                                ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r );
 +                                ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r );
 +    virtual                     ~ScExternalDoubleRefToken();
 +
-+    virtual USHORT                  GetIndex() const;
++    virtual USHORT                 GetIndex() const;
++    virtual const String&          GetString() const;
 +    virtual const ComplRefData&    GetDoubleRef() const;
 +    virtual ComplRefData&          GetDoubleRef();
 +    virtual BOOL                    operator==( const ScToken& rToken ) const;
@@ -451,17 +587,54 @@
  {
  private:
 diff --git sc/inc/tokenarray.hxx sc/inc/tokenarray.hxx
-index 1d903ce..f7c4d6b 100644
+index 1d903ce..1e94c2f 100644
 --- sc/inc/tokenarray.hxx
 +++ sc/inc/tokenarray.hxx
-@@ -193,6 +193,7 @@ public:
+@@ -193,6 +193,9 @@ public:
      ScToken* AddDoubleReference( const ComplRefData& rRef );
      ScToken* AddName( USHORT n );
      ScToken* AddMatrix( ScMatrix* p );
 +    ScToken* AddExternalName( sal_uInt16 nFileId, const String& rName );
++    ScToken* AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
++    ScToken* AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef );
      ScToken* AddExternal( const sal_Unicode* pStr );
      /** Xcl import may play dirty tricks with OpCode!=ocExternal.
          Others don't use! */
+diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
+index a68efc0..a1e3c12 100644
+--- sc/source/core/data/cell.cxx
++++ sc/source/core/data/cell.cxx
+@@ -87,6 +87,30 @@ static const sal_Char __FAR_DATA msgDbgInfinity[] =
+ 	"NICHTS anruehren und ER bescheid sagen!";
+ #endif
+ 
++
++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;
++};
++
++}
+ // -----------------------------------------------------------------------
+ 
+ ScBaseCell::ScBaseCell( CellType eNewType ) :
 diff --git sc/source/core/data/documen2.cxx sc/source/core/data/documen2.cxx
 index 85ad0e5..f04061f 100644
 --- sc/source/core/data/documen2.cxx
@@ -532,8 +705,239 @@
  BOOL ScDocument::InsertLinkedEmptyTab( SCTAB& rnTab, const String& rFileName,
          const String& rFilterName, const String& rFilterOpt, const String& rTabName )
  {
+diff --git sc/source/core/tool/address.cxx sc/source/core/tool/address.cxx
+index 2cb5dce..39cdd8e 100644
+--- sc/source/core/tool/address.cxx
++++ sc/source/core/tool/address.cxx
+@@ -35,6 +35,7 @@
+ #include "global.hxx"
+ #include "compiler.hxx"
+ #include "document.hxx"
++#include "externalrefmgr.hxx"
+ 
+ #include "globstr.hrc"
+ #include <sal/alloca.h>
+@@ -45,6 +46,31 @@
+ #include <tools/urlobj.hxx>
+ 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 ScAddress::Details ScAddress::detailsOOOa1( CONV_OOO, 0, 0 );
+ 
+@@ -713,15 +739,16 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+ }
+ 
+ static USHORT
+-lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p,
+-                         ScDocument* pDoc, ScAddress& rAddr )
++lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, 
++                         ScAddress::ExternalInfo* pExtInfo = NULL )
+ {
++    StackPrinter aStack("::lcl_ScAddress_Parse_OOo");
+     USHORT  nRes = 0;
+     String  aDocName;       // der pure Dokumentenname
+     String  aDocTab;        // zusammengesetzt fuer Table
+     String  aTab;
+     BOOL    bExtDoc = FALSE;
+-    BOOL    bNeedExtTab = FALSE;
++    const ScAddress aCurPos(rAddr);
+ 
+     // Lets see if this is a reference to something in an external file.
+     // A Documentname is always quoted and has a trailing #
+@@ -795,35 +822,11 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p,
+         }
+         if( *p++ != '.' )
+             nBits = 0;
+-        if ( pDoc )
++
++        if (pDoc)
+         {
+-            if ( bExtDoc )
+-            {
+-                bExternal = TRUE;
+-                aDocTab += aTab;    // "'Doc'#Tab"
+-                if ( !pDoc->GetTable( aDocTab, nTab ) )
+-                {
+-                    if ( pDoc->ValidTabName( aTab ) )
+-                    {
+-                        aDocName = ScGlobal::GetAbsDocName( aDocName,
+-                            pDoc->GetDocumentShell() );
+-                        aDocTab = ScGlobal::GetDocTabName( aDocName, aTab );
+-                        if ( !pDoc->GetTable( aDocTab, nTab ) )
+-                        {
+-                            // erst einfuegen, wenn Rest der Ref ok
+-                            bNeedExtTab = TRUE;
+-                            nBits = 0;
+-                        }
+-                    }
+-                    else
+-                        nBits = 0;
+-                }
+-            }
+-            else
+-            {
+-                if ( !pDoc->GetTable( aTab, nTab ) )
+-                    nBits = 0;
+-            }
++            if ( !pDoc->GetTable( aTab, nTab ) )
++                nBits = 0;
+         }
+         else
+             nBits = 0;
+@@ -884,16 +887,33 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p,
+         if( !nBits )
+             p = q;
+     }
+-    if ( bNeedExtTab )
++
++    if (bExtDoc)
+     {
+-        if ( (nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL)
+-          && pDoc->LinkExternalTab( nTab, aDocTab, aDocName, aTab ) )
++        ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++        pRefMgr->convertToAbsName(aDocName);
++        fprintf(stdout, "lcl_ScAddress_Parse_OOo:   doc name = '%s'; tab = '%s' col = %d row = %ld\n",
++                rtl::OUStringToOString(aDocName, RTL_TEXTENCODING_UTF8).getStr(),
++                rtl::OUStringToOString(aTab, RTL_TEXTENCODING_UTF8).getStr(), nCol, nRow);
++
++        // TODO: Make sure the document exists!
++
++        sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName);
++        if (pExtInfo && !pExtInfo->mbExternal)
++        {
++            pExtInfo->mbExternal = true;
++            pExtInfo->maTabName = aTab;
++            pExtInfo->mnFileId = nFileId;
++        }
++
++        if (pRefMgr->getSingleRefToken(nFileId, aTab, ScAddress(nCol, nRow, 0), NULL, &nTab))
+         {
+             nRes |= SCA_VALID_TAB;
+         }
+         else
+-            nRes = 0;   // #NAME? statt #REF!, Dateiname bleibt erhalten
++            nRes = 0;
+     }
++
+     if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL)
+             && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) )
+     {   // keine Row, keine Tab, aber Col => DM (...), B (...) o.ae.
+@@ -912,9 +932,8 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p,
+ }
+ 
+ static USHORT
+-lcl_ScAddress_Parse ( BOOL& bExternal, const sal_Unicode* p,
+-                      ScDocument* pDoc, ScAddress& rAddr,
+-                      const ScAddress::Details& rDetails )
++lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
++                      const ScAddress::Details& rDetails, ScAddress::ExternalInfo* pExtInfo = NULL )
+ {
+     if( !*p )
+         return 0;
+@@ -924,7 +943,7 @@ lcl_ScAddress_Parse ( BOOL& bExternal, const sal_Unicode* p,
+     default :
+     case ScAddress::CONV_OOO:
+         {
+-            return lcl_ScAddress_Parse_OOo( bExternal, p, pDoc, rAddr );
++            return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo );
+         }
+ 
+     case ScAddress::CONV_XL_A1:
+@@ -949,9 +968,8 @@ bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString,
+                        SCTAB nDefTab, ScRefAddress& rRefAddress,
+                        const ScAddress::Details& rDetails )
+ {
+-    BOOL bExternal = FALSE;
+     ScAddress aAddr( 0, 0, nDefTab );
+-    USHORT nRes = lcl_ScAddress_Parse( bExternal, rRefString.GetBuffer(), pDoc, aAddr, rDetails );
++    USHORT nRes = lcl_ScAddress_Parse( rRefString.GetBuffer(), pDoc, aAddr, rDetails, NULL );
+     if( nRes & SCA_VALID )
+     {
+         rRefAddress.Set( aAddr,
+@@ -988,10 +1006,9 @@ bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab
+ 
+ 
+ USHORT ScAddress::Parse( const String& r, ScDocument* pDoc,
+-                         const Details& rDetails)
++                         const Details& rDetails, ExternalInfo* pExtInfo )
+ {
+-    BOOL bExternal = FALSE;
+-    return lcl_ScAddress_Parse( bExternal, r.GetBuffer(), pDoc, *this, rDetails );
++    return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo );
+ }
+ 
+ 
+@@ -1060,7 +1077,7 @@ void ScRange::ExtendTo( const ScRange& rRange )
+ }
+ 
+ static USHORT
+-lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc )
++lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL )
+ {
+     USHORT nRes1 = 0, nRes2 = 0;
+     xub_StrLen nTmp = 0;
+@@ -1073,13 +1090,12 @@ lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc )
+         String aTmp( r );
+         sal_Unicode* p = aTmp.GetBufferAccess();
+         p[ nPos ] = 0;
+-        BOOL bExternal = FALSE;
+-        if( (nRes1 = lcl_ScAddress_Parse_OOo( bExternal, p, pDoc, aRange.aStart ) ) != 0 )
++        if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo ) ) != 0 )
+         {
+             aRange.aEnd = aRange.aStart;  // die Tab _muss_ gleich sein, so ist`s weniger Code
+-            if ( (nRes2 = lcl_ScAddress_Parse_OOo( bExternal, p + nPos+ 1, pDoc, aRange.aEnd ) ) != 0 )
++            if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, NULL ) ) != 0 )
+             {
+-                if ( bExternal && aRange.aStart.Tab() != aRange.aEnd.Tab() )
++                if ( pExtInfo && pExtInfo->mbExternal && aRange.aStart.Tab() != aRange.aEnd.Tab() )
+                     nRes2 &= ~SCA_VALID_TAB;    // #REF!
+                 else
+                 {
+@@ -1132,7 +1148,7 @@ lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc )
+ }
+ 
+ USHORT ScRange::Parse( const String& r, ScDocument* pDoc,
+-                       const ScAddress::Details& rDetails )
++                       const ScAddress::Details& rDetails, ScAddress::ExternalInfo* pExtInfo )
+ {
+     if ( r.Len() <= 0 )
+         return 0;
+@@ -1141,7 +1157,7 @@ USHORT ScRange::Parse( const String& r, ScDocument* pDoc,
+     {
+     default :
+     case ScAddress::CONV_OOO:
+-        return lcl_ScRange_Parse_OOo( *this, r, pDoc );
++        return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo );
+ 
+     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..c763f91 100644
+index f88d5d3..563adf9 100644
 --- sc/source/core/tool/compiler.cxx
 +++ sc/source/core/tool/compiler.cxx
 @@ -74,9 +74,38 @@
@@ -759,7 +1163,7 @@
          return pCharClass->parseAnyToken( rFormula,
                  nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
      }
-@@ -1368,6 +1565,16 @@ struct ConventionOOO_A1 : public Convention_A1
+@@ -1368,6 +1565,81 @@ struct ConventionOOO_A1 : public Convention_A1
  
          return sal_Unicode(0);
      }
@@ -773,10 +1177,75 @@
 +    {
 +        return lcl_makeExternalNameStr(rFile, rName, sal_Unicode('#'));
 +    }
++
++    bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId, 
++                                   const String& rTabName, const SingleRefData& rRef, 
++                                   ScExternalRefManager* pRefMgr, bool bDisplayTabName ) const
++    {
++        if (bDisplayTabName)
++        {
++            String aFile;
++            const String* p = pRefMgr->getExternalFileName(nFileId);
++            if (p)
++                aFile = *p;
++            aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
++    
++            rBuffer.append(sal_Unicode('\''));
++            rBuffer.append(aFile);
++            rBuffer.append(sal_Unicode('\''));
++            rBuffer.append(sal_Unicode('#'));
++    
++            // external reference is always 3D and the sheet is absolute.
++            rBuffer.append(sal_Unicode('$'));
++            bool bQuote = (rTabName.Search(sal_Unicode(' '), 0) != STRING_NOTFOUND);
++            if (bQuote)
++                rBuffer.append(sal_Unicode('\''));
++            rBuffer.append(rTabName);
++            if (bQuote)
++                rBuffer.append(sal_Unicode('\''));
++
++            rBuffer.append(sal_Unicode('.'));
++        }
++
++        if (!rRef.IsColRel())
++            rBuffer.append(sal_Unicode('$'));
++        rBuffer.append(MakeColStr(rRef.nCol));
++        if (!rRef.IsRowRel())
++            rBuffer.append(sal_Unicode('$'));
++        rBuffer.append(MakeRowStr(rRef.nRow));
++
++        return true;
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        SingleRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        ComplRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true))
++            return;
++
++        rBuffer.append(sal_Unicode(':'));
++
++        // TODO: Get the real table name of the last table.
++        makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref2, pRefMgr, (aRef.Ref1.nTab != aRef.Ref2.nTab));
++    }
  };
  
  
-@@ -1489,6 +1696,16 @@ struct ConventionXL
+@@ -1489,6 +1761,16 @@ struct ConventionXL
          }
          return sal_Unicode(0);
      }
@@ -793,7 +1262,7 @@
  };
  
  struct ConventionXL_A1 : public Convention_A1, public ConventionXL
-@@ -1587,6 +1804,16 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+@@ -1587,6 +1869,16 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
      {
          return ConventionXL::getSpecialSymbol(eSymType);
      }
@@ -810,7 +1279,7 @@
  };
  
  static const ConventionXL_A1 ConvXL_A1;
-@@ -1714,6 +1941,16 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
+@@ -1714,6 +2006,16 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
      {
          return ConventionXL::getSpecialSymbol(eSymType);
      }
@@ -827,7 +1296,7 @@
  };
  
  static const ConventionXL_R1C1 ConvXL_R1C1;
-@@ -1888,6 +2125,7 @@ sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub
+@@ -1888,6 +2190,7 @@ sal_Unicode* lcl_UnicodeStrNCpy( sal_Unicode* pDst, const sal_Unicode* pSrc, xub
  
  xub_StrLen ScCompiler::NextSymbol(bool bInArray)
  {
@@ -835,7 +1304,7 @@
      cSymbol[MAXSTRLEN-1] = 0;       // Stopper
      sal_Unicode* pSym = cSymbol;
      const sal_Unicode* const pStart = aFormula.GetBuffer();
-@@ -1912,6 +2150,11 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -1912,6 +2215,11 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
      bool bAutoIntersection = false;
      int nRefInSheetName = 0;
      mnPredetectedReference = 0;
@@ -847,7 +1316,7 @@
      // try to parse simple tokens before calling i18n parser
      while ((c != 0) && (eState != ssStop) )
      {
-@@ -2169,7 +2412,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2169,7 +2477,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
                      static const int kQuote = kInc * 2;
                      static const int kPast = kInc * 3;
                      bool bAddToSymbol = true;
@@ -856,7 +1325,7 @@
                      {
                          // eat it, no sheet name
                          bAddToSymbol = false;
-@@ -2184,7 +2427,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2184,7 +2492,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
                      }
                      else if (nRefInSheetName < kPast)
                      {
@@ -865,7 +1334,7 @@
                              nRefInSheetName += kDollar;
                          else if ('\'' == c)
                          {
-@@ -2235,6 +2478,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2235,6 +2543,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
          cLast = c;
          c = *pSrc;
      }
@@ -873,7 +1342,7 @@
      if ( bi18n )
      {
          nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces );
-@@ -2287,6 +2531,9 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+@@ -2287,6 +2596,9 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
          aCorrectedSymbol = cSymbol;
      if (bAutoIntersection && nSpaces > 1)
          --nSpaces;  // replace '!!' with only one space
@@ -883,7 +1352,91 @@
      return nSpaces;
  }
  
-@@ -2669,6 +2916,30 @@ BOOL ScCompiler::IsNamedRange( const String& rUpperName )
+@@ -2506,7 +2818,8 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
+ {
+     ScRange aRange( aPos, aPos );
+     const ScAddress::Details aDetails( pConv->meConv, aPos );
+-    USHORT nFlags = aRange.Parse( rName, pDoc, aDetails );
++    ScAddress::ExternalInfo aExtInfo;
++    USHORT nFlags = aRange.Parse( rName, pDoc, aDetails, &aExtInfo );
+     if( nFlags & SCA_VALID )
+     {
+         ScRawToken aToken;
+@@ -2525,23 +2838,41 @@ BOOL ScCompiler::IsDoubleReference( const String& rName )
+             aRef.Ref2.SetTabDeleted( TRUE );        // #REF!
+         aRef.Ref2.SetFlag3D( ( nFlags & SCA_TAB2_3D ) != 0 );
+         aRef.CalcRelFromAbs( aPos );
+-        aToken.SetDoubleReference( aRef );
++        if (aExtInfo.mbExternal)
++        {
++            aToken.SetExternalDoubleRef(aExtInfo.mnFileId, aExtInfo.maTabName, aRef);
++        }
++        else
++        {
++            aToken.SetDoubleReference(aRef);
++        }
+         pRawToken = aToken.Clone();
+     }
+ 
++    bool bRes = (nFlags & SCA_VALID) != 0;
++    fprintf(stdout, "ScCompiler::IsDoubleReference:   is double ref? (%s)\n", bRes?"yes":"no");
+     return ( nFlags & SCA_VALID ) != 0;
+ }
+ 
+ 
+ BOOL ScCompiler::IsSingleReference( const String& rName )
+ {
++    StackPrinter aStack("ScCompiler::IsSingleReference");
++    fprintf(stdout, "ScCompiler::IsSingleReference:   symbol ='%s'\n", rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8).getStr());
++
+     ScAddress aAddr( aPos );
+     const ScAddress::Details aDetails( pConv->meConv, aPos );
+-    USHORT nFlags = aAddr.Parse( rName, pDoc, aDetails );
++    ScAddress::ExternalInfo aExtInfo;
++    USHORT nFlags = aAddr.Parse( rName, pDoc, aDetails, &aExtInfo );
+     // Something must be valid in order to recognize Sheet1.blah or blah.a1
+     // as a (wrong) reference.
+     if( nFlags & ( SCA_VALID_COL|SCA_VALID_ROW|SCA_VALID_TAB ) )
+     {
++        if (aExtInfo.mbExternal)
++            fprintf(stdout, "ScCompiler::IsSingleReference:   this is an external single ref\n");
++        else
++            fprintf(stdout, "ScCompiler::IsSingleReference:   this is an internal single ref\n");
++
+         ScRawToken aToken;
+         SingleRefData aRef;
+         aRef.InitAddress( aAddr );
+@@ -2561,16 +2892,28 @@ BOOL ScCompiler::IsSingleReference( const String& rName )
+             nFlags |= SCA_VALID;
+         }
+         aRef.CalcRelFromAbs( aPos );
+-        aToken.SetSingleReference( aRef );
++        fprintf(stdout, "ScCompiler::IsSingleReference:   abs col = %d; row = %d; tab = %d\n", aRef.nCol, aRef.nRow, aRef.nTab);
++        fprintf(stdout, "ScCompiler::IsSingleReference:   rel col = %d; row = %d; tab = %d\n", 
++                aRef.nRelCol, aRef.nRelRow, aRef.nRelTab);
++        fprintf(stdout, "ScCompiler::IsSingleReference:   col rel (%d); row rel (%d); tab rel (%d)\n", 
++                aRef.IsColRel(), aRef.IsRowRel(), aRef.IsTabRel());
++
++        if (aExtInfo.mbExternal)
++            aToken.SetExternalSingleRef(aExtInfo.mnFileId, aExtInfo.maTabName, aRef);
++        else
++            aToken.SetSingleReference(aRef);
+         pRawToken = aToken.Clone();
+     }
+ 
++    fprintf(stdout, "ScCompiler::IsSingleReference:   is single ref? (%s)\n", (nFlags&SCA_VALID)?"yes":"no");
+     return ( nFlags & SCA_VALID ) != 0;
+ }
+ 
+ 
+ BOOL ScCompiler::IsReference( const String& rName )
+ {
++    StackPrinter aStack("ScCompiler::IsReference");
++
+     // 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 )
          return FALSE;
  }
  
@@ -914,7 +1467,7 @@
  BOOL ScCompiler::IsDBRange( const String& rName )
  {
      USHORT n;
-@@ -3267,6 +3538,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
+@@ -3267,6 +3634,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
                && !(bAllowBooleans && IsBoolean( aUpper ))
                && !IsValue( aUpper )
                && !IsNamedRange( aUpper )
@@ -922,7 +1475,7 @@
                && !IsDBRange( aUpper )
                && !IsColRowName( aUpper )
                && !(bMayBeFuncName && IsMacro( aUpper ))
-@@ -3593,6 +3865,69 @@ BOOL ScCompiler::GetToken()
+@@ -3593,6 +3961,69 @@ BOOL ScCompiler::GetToken()
      }
      if( pToken->GetOpCode() == ocSubTotal )
          glSubTotal = TRUE;
@@ -959,7 +1512,7 @@
 +
 +                aData.CalcAbsIfRel(aPos);
 +                ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
-+                ScToken* pNew = pRefMgr->getSingleRefToken(pToken->GetIndex(), aAddr, &aPos);
++                ScToken* pNew = pRefMgr->getSingleRefToken(pToken->GetIndex(), pToken->GetString(), aAddr, &aPos, NULL);
 +                if (pNew)
 +                {
 +                    pToken = pNew->Clone();
@@ -978,7 +1531,7 @@
 +                aData.CalcAbsIfRel(aPos);
 +                ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab, 
 +                               aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
-+                ScTokenArray* pNew = pRefMgr->getDoubleRefTokens(pToken->GetIndex(), aRange, &aPos);
++                ScTokenArray* pNew = pRefMgr->getDoubleRefTokens(pToken->GetIndex(), pToken->GetString(), aRange, &aPos);
 +                if (pNew)
 +                {
 +                    PushTokenArray(pNew->Clone(), true);
@@ -992,46 +1545,323 @@
      else if( pToken->GetOpCode() == ocName )
      {
          ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
-@@ -5543,6 +5878,15 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
+@@ -5543,6 +5974,7 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
      BOOL bSpaces = FALSE;
      ScToken* t = pTokenP;
      OpCode eOp = t->GetOpCode();
-+    if (eOp == ocExternalName)
-+    {
-+        const String *pStr = pDoc->GetExternalRefManager()->getExternalFileName(t->GetIndex());
-+        if (pStr)
-+        {
-+            rBuffer.append(pConv->makeExternalNameStr(*pStr, t->GetString()));
-+        }
-+    }
 +
      if( eOp >= ocAnd && eOp <= ocOr )
      {
          // AND, OR infix?
+@@ -5590,111 +6022,141 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
+         DBG_ERRORFILE("unknown OpCode");
+         rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
+     }
+-    if( bNext ) switch( t->GetType() )
++    if (bNext) 
+     {
+-        case svDouble:
+-            AppendDouble( rBuffer, t->GetDouble() );
+-        break;
+-
+-        case svString:
+-            if( eOp == ocBad )
+-                rBuffer.append(t->GetString());
+-            else
+-                AppendString( rBuffer, t->GetString() );
+-            break;
+-        case svSingleRef:
++        if (eOp == ocExternalName)
+         {
+-            SingleRefData& rRef = t->GetSingleRef();
+-            ComplRefData aRef;
+-            aRef.Ref1 = aRef.Ref2 = rRef;
+-            if ( eOp == ocColRowName )
++            fprintf(stdout, "ScCompiler::CreateStringFromToken:   external name token\n");
++            ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++            switch (t->GetType())
+             {
+-                rRef.CalcAbsIfRel( aPos );
+-                if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) )
+-                {
+-                    String aStr;
+-                    pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr );
+-                    EnQuote( aStr );
+-                    rBuffer.append(aStr);
+-                }
+-                else
++                case svExternalName:
+                 {
+-                    rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
+-                    pConv->MakeRefStr (rBuffer, *this, aRef, TRUE );
++                    const String *pStr = pRefMgr->getExternalFileName(t->GetIndex());
++                    String aFileName = pStr ? *pStr : ScGlobal::GetRscString(STR_NO_NAME_REF);
++                    rBuffer.append(pConv->makeExternalNameStr(
++                        aFileName, t->GetString()));
+                 }
++                break;
++                case svSingleRef:
++                    pConv->makeExternalRefStr(
++                        rBuffer, *this, t->GetIndex(), t->GetString(), t->GetSingleRef(), pRefMgr);
++                break;
++                case svDoubleRef:
++                    pConv->makeExternalRefStr(
++                        rBuffer, *this, t->GetIndex(), t->GetString(), t->GetDoubleRef(), pRefMgr);
++                break;
+             }
+-            else
+-                pConv->MakeRefStr( rBuffer, *this, aRef, TRUE );
+         }
+-            break;
+-        case svDoubleRef:
+-            pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE );
+-            break;
+-        case svMatrix:
+-            CreateStringFromScMatrix( rBuffer, t->GetMatrix() );
+-            break;
+-
+-        case svIndex:
++        else
+         {
+-            rtl::OUStringBuffer aBuffer;
+-            switch ( eOp )
++            switch( t->GetType() )
+             {
+-                case ocName:
++                case svDouble:
++                    AppendDouble( rBuffer, t->GetDouble() );
++                break;
++        
++                case svString:
++                    if( eOp == ocBad )
++                        rBuffer.append(t->GetString());
++                    else
++                        AppendString( rBuffer, t->GetString() );
++                    break;
++                case svSingleRef:
+                 {
+-                    ScRangeData* pData = pDoc->GetRangeName()->FindIndex(t->GetIndex());
+-                    if (pData)
++                    SingleRefData& rRef = t->GetSingleRef();
++                    ComplRefData aRef;
++                    aRef.Ref1 = aRef.Ref2 = rRef;
++                    if ( eOp == ocColRowName )
+                     {
+-                        if (pData->HasType(RT_SHARED))
+-                            pData->UpdateSymbol( aBuffer, aPos, GetGrammar());
++                        rRef.CalcAbsIfRel( aPos );
++                        if ( pDoc->HasStringData( rRef.nCol, rRef.nRow, rRef.nTab ) )
++                        {
++                            String aStr;
++                            pDoc->GetString( rRef.nCol, rRef.nRow, rRef.nTab, aStr );
++                            EnQuote( aStr );
++                            rBuffer.append(aStr);
++                        }
+                         else
+-                            aBuffer.append(pData->GetName());
++                        {
++                            rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
++                            pConv->MakeRefStr (rBuffer, *this, aRef, TRUE );
++                        }
+                     }
++                    else
++                        pConv->MakeRefStr( rBuffer, *this, aRef, TRUE );
+                 }
+-                break;
+-                case ocDBArea:
++                    break;
++                case svDoubleRef:
++                    pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE );
++                    break;
++                case svMatrix:
++                    CreateStringFromScMatrix( rBuffer, t->GetMatrix() );
++                    break;
++        
++                case svIndex:
+                 {
+-                    ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex());
+-                    if (pDBData)
+-                        aBuffer.append(pDBData->GetName());
++                    rtl::OUStringBuffer aBuffer;
++                    switch ( eOp )
++                    {
++                        case ocName:
++                        {
++                            ScRangeData* pData = pDoc->GetRangeName()->FindIndex(t->GetIndex());
++                            if (pData)
++                            {
++                                if (pData->HasType(RT_SHARED))
++                                    pData->UpdateSymbol( aBuffer, aPos, GetGrammar());
++                                else
++                                    aBuffer.append(pData->GetName());
++                            }
++                        }
++                        break;
++                        case ocDBArea:
++                        {
++                            ScDBData* pDBData = pDoc->GetDBCollection()->FindIndex(t->GetIndex());
++                            if (pDBData)
++                                aBuffer.append(pDBData->GetName());
++                        }
++                        break;
++                        default:
++                            ;   // nothing
++                    }
++                    if ( aBuffer.getLength() )
++                        rBuffer.append(aBuffer);
++                    else
++                        rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
++                    break;
+                 }
+-                break;
+-                default:
+-                    ;   // nothing
+-            }
+-            if ( aBuffer.getLength() )
+-                rBuffer.append(aBuffer);
+-            else
+-                rBuffer.append(ScGlobal::GetRscString(STR_NO_NAME_REF));
+-            break;
+-        }
+-        case svExternal:
+-        {
+-            // mapped or translated name of AddIns
+-            String aAddIn( t->GetExternal() );
+-            bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
+-            if (!bMapped && mxSymbols->hasExternals())
+-            {
+-                ScExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
+-                if (iLook != mxSymbols->getReverseExternalHashMap()->end())
++                case svExternal:
+                 {
+-                    aAddIn = (*iLook).second;
+-                    bMapped = true;
++                    // mapped or translated name of AddIns
++                    String aAddIn( t->GetExternal() );
++                    bool bMapped = mxSymbols->isPODF();     // ODF 1.1 directly uses programmatical name
++                    if (!bMapped && mxSymbols->hasExternals())
++                    {
++                        ScExternalHashMap::const_iterator iLook = mxSymbols->getReverseExternalHashMap()->find( aAddIn);
++                        if (iLook != mxSymbols->getReverseExternalHashMap()->end())
++                        {
++                            aAddIn = (*iLook).second;
++                            bMapped = true;
++                        }
++                    }
++                    if (!bMapped && !mxSymbols->isEnglish())
++                        ScGlobal::GetAddInCollection()->LocalizeString( aAddIn );
++                    rBuffer.append(aAddIn);
+                 }
+-            }
+-            if (!bMapped && !mxSymbols->isEnglish())
+-                ScGlobal::GetAddInCollection()->LocalizeString( aAddIn );
+-            rBuffer.append(aAddIn);
++                    break;
++                case svByte:
++                case svJump:
++                case svFAP:
++                case svMissing:
++                case svSep:
++                    break;      // Opcodes
++                default:
++                    DBG_ERROR("ScCompiler:: GetStringFromToken errUnknownVariable");
++            }                                           // of switch
+         }
+-            break;
+-        case svByte:
+-        case svJump:
+-        case svFAP:
+-        case svMissing:
+-        case svSep:
+-            break;      // Opcodes
+-        default:
+-            DBG_ERROR("ScCompiler:: GetStringFromToken errUnknownVariable");
+-    }                                           // of switch
++    }
+     if( bSpaces )
+         rBuffer.append(sal_Unicode(' '));
+     if ( bAllowArrAdvance )
 diff --git sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx
-index a20cbd5..5486519 100644
+index a20cbd5..25090a8 100644
 --- sc/source/core/tool/token.cxx
 +++ sc/source/core/tool/token.cxx
-@@ -54,6 +54,8 @@
+@@ -54,6 +54,33 @@
  #include "parclass.hxx"
  #include "jumpmatrix.hxx"
  
 +using ::std::vector;
 +
- // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
- // SubCode via ScTokenIterator Push/Pop moeglich
- IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 )
-@@ -209,6 +211,19 @@ void ScRawToken::SetName( USHORT n )
-     nRefCnt = 0;
- }
- 
-+void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
-+{
-+    eOp = ocExternalName;
-+    eType = svExternalName;
-+    nRefCnt = 0;
 +
-+    extname.nFileId = nFileId;
++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;
++};
++
++}
++
+ // ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch
+ // SubCode via ScTokenIterator Push/Pop moeglich
+ IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 )
+@@ -209,6 +236,51 @@ void ScRawToken::SetName( USHORT n )
+     nRefCnt = 0;
+ }
+ 
++void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
++{
++    eOp = ocExternalName;
++    eType = svSingleRef;
++    nRefCnt = 0;
++
++    extref.nFileId = nFileId;
++    extref.aRef.Ref1 = 
++    extref.aRef.Ref2 = rRef;
++
++    xub_StrLen n = rTabName.Len();
++    fprintf(stdout, "ScRawToken::SetExternalSingleRef:   tab name = '%s'; len = %d\n", 
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr(), n);
++
++    memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
++    extref.cTabName[n] = 0;
++}
++
++void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef )
++{
++    eOp = ocExternalName;
++    eType = svDoubleRef;
++    nRefCnt = 0;
++
++    extref.nFileId = nFileId;
++    extref.aRef = rRef;
++
++    xub_StrLen n = rTabName.Len();
++    memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
++    extref.cTabName[n] = 0;
++}
++
++void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
++{
++    eOp = ocExternalName;
++    eType = svExternalName;
++    nRefCnt = 0;
++
++    extname.nFileId = nFileId;
 +
 +    xub_StrLen n = rName.Len();
 +    memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode));
@@ -1041,19 +1871,81 @@
  ComplRefData& ScRawToken::GetReference()
  {
      DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "GetReference: no Ref" );
-@@ -269,6 +284,7 @@ ScRawToken* ScRawToken::Clone() const
-             case svSingleRef:
-             case svDoubleRef:   n += sizeof(aRef); break;
-             case svMatrix:      n += sizeof(ScMatrix*); break;
-+            case svExternalName: n += sizeof(extname); break;
-             case svIndex:       n += sizeof(USHORT); break;
-             case svJump:        n += nJump[ 0 ] * 2 + 2; break;
-             case svExternal:    n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
-@@ -325,8 +341,14 @@ ScToken* ScRawToken::CreateToken() const
-             return new ScMatrixToken( pMat );
+@@ -260,22 +332,34 @@ ScRawToken* ScRawToken::Clone() const
+         static USHORT nOffset = lcl_ScRawTokenOffset();     // offset of sbyte
+         USHORT n = nOffset;
+ 
+-        switch( eType )
++        if (eOp == ocExternalName)
+         {
+-            case svSep:         break;
+-            case svByte:        n += sizeof(ScRawToken::sbyte); break;
+-            case svDouble:      n += sizeof(double); break;
+-            case svString:      n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
+-            case svSingleRef:
+-            case svDoubleRef:   n += sizeof(aRef); break;
+-            case svMatrix:      n += sizeof(ScMatrix*); break;
+-            case svIndex:       n += sizeof(USHORT); break;
+-            case svJump:        n += nJump[ 0 ] * 2 + 2; break;
+-            case svExternal:    n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
+-            default:
+-                                {
+-                                    DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
+-                                }
++            switch (eType)
++            {
++                case svSingleRef:
++                case svDoubleRef:    n += sizeof(extref); break;
++                case svExternalName: n += sizeof(extname); break;
++            }
++        }
++        else
++        {
++            switch( eType )
++            {
++                case svSep:         break;
++                case svByte:        n += sizeof(ScRawToken::sbyte); break;
++                case svDouble:      n += sizeof(double); break;
++                case svString:      n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
++                case svSingleRef:
++                case svDoubleRef:   n += sizeof(aRef); break;
++                case svMatrix:      n += sizeof(ScMatrix*); break;
++                case svIndex:       n += sizeof(USHORT); break;
++                case svJump:        n += nJump[ 0 ] * 2 + 2; break;
++                case svExternal:    n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
++                default:
++                {
++                    DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
++                }
++            }
+         }
+         p = (ScRawToken*) new BYTE[ n ];
+         memcpy( p, this, n * sizeof(BYTE) );
+@@ -311,12 +395,22 @@ ScToken* ScRawToken::CreateToken() const
+         case svSingleRef :
+             if (eOp == ocPush)
+                 return new ScSingleRefToken( aRef.Ref1 );
++            else if (eOp == ocExternalName)
++            {
++                String aTabName(extref.cTabName);
++                return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1);
++            }
+             else
+                 return new ScSingleRefOpToken( eOp, aRef.Ref1 );
          //break;
+         case svDoubleRef :
+             if (eOp == ocPush)
+                 return new ScDoubleRefToken( aRef );
++            else if (eOp == ocExternalName)
++            {
++                String aTabName(extref.cTabName);
++                return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef);
++            }
+             else
+                 return new ScDoubleRefOpToken( eOp, aRef );
+         //break;
+@@ -327,6 +421,11 @@ ScToken* ScRawToken::CreateToken() const
          case svIndex :
-+            fprintf(stdout, "ScRawToken::CreateToken:   creating index token ... (op = %d)\n", eOp);
              return new ScIndexToken( eOp, nIndex );
          //break;
 +        case svExternalName:
@@ -1064,7 +1956,7 @@
          case svJump :
              return new ScJumpToken( eOp, (short*) nJump );
          //break;
-@@ -478,6 +500,7 @@ BOOL ScToken::IsMatrixFunction() const
+@@ -478,6 +577,7 @@ BOOL ScToken::IsMatrixFunction() const
  
  ScToken* ScToken::Clone() const
  {
@@ -1072,7 +1964,7 @@
      switch ( GetType() )
      {
          case svByte :
-@@ -487,20 +510,24 @@ ScToken* ScToken::Clone() const
+@@ -487,20 +587,24 @@ ScToken* ScToken::Clone() const
              return new ScDoubleToken( *static_cast<const ScDoubleToken*>(this) );
          //break;
          case svString :
@@ -1100,7 +1992,7 @@
              else
                  return new ScDoubleRefOpToken( *static_cast<const ScDoubleRefOpToken*>(this) );
          //break;
-@@ -522,6 +549,9 @@ ScToken* ScToken::Clone() const
+@@ -522,6 +626,9 @@ ScToken* ScToken::Clone() const
          case svExternal :
              return new ScExternalToken( *static_cast<const ScExternalToken*>(this) );
          //break;
@@ -1110,15 +2002,48 @@
          case svFAP :
              return new ScFAPToken( *static_cast<const ScFAPToken*>(this) );
          //break;
-@@ -1035,6 +1065,150 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
+@@ -660,6 +767,7 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2,
+         return NULL;
+ 
+     ScTokenRef xRes;
++    bool bExternal = rTok1.GetOpCode() == ocExternalName;
+     if (sv1 == svSingleRef && sv2 == svSingleRef)
+     {
+         // Range references like Sheet1.A1:A2 are generalized and built by
+@@ -671,7 +779,10 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2,
+         aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef();
+         aRef.Ref2.SetFlag3D( false);
+         aRef.Extend( p2->GetSingleRef(), rPos);
+-        xRes = new ScDoubleRefToken( aRef);
++        if (bExternal)
++            xRes = new ScExternalDoubleRefToken(rTok1.GetIndex(), rTok1.GetString(), aRef);
++        else
++            xRes = new ScDoubleRefToken( aRef);
+     }
+     else
+     {
+@@ -694,7 +805,10 @@ ScTokenRef ScToken::ExtendRangeReference( ScToken & rTok1, ScToken & rTok2,
+         {
+             if (!pRefList->size())
+                 return NULL;
+-            xRes = new ScDoubleRefToken( (*pRefList)[0] );
++            if (bExternal)
++                xRes = new ScExternalDoubleRefToken(rTok1.GetIndex(), rTok1.GetString(), (*pRefList)[0]);
++            else
++                xRes = new ScDoubleRefToken( (*pRefList)[0] );
+         }
+         if (!xRes)
+             return NULL;    // shouldn't happen..
+@@ -1035,6 +1149,170 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
      return ScToken::operator==( r ) && nIndex == r.GetIndex();
  }
  
 +// ============================================================================
 +
-+ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const SingleRefData& r ) :
++ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& r ) :
 +    ScOpToken(ocExternalName, svSingleRef),
 +    mnFileId(nFileId),
++    maTabName(rTabName),
 +    maSingleRef(r)
 +{
 +}
@@ -1126,6 +2051,7 @@
 +ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) :
 +    ScOpToken(r), 
 +    mnFileId(r.mnFileId),
++    maTabName(r.maTabName),
 +    maSingleRef(r.maSingleRef)
 +{
 +}
@@ -1139,6 +2065,11 @@
 +    return mnFileId;
 +}
 +
++const String& ScExternalSingleRefToken::GetString() const
++{
++    return maTabName;
++}
++
 +const SingleRefData& ScExternalSingleRefToken::GetSingleRef() const
 +{
 +    return maSingleRef;
@@ -1157,14 +2088,18 @@
 +    if (mnFileId != r.GetIndex())
 +        return false;
 +
++    if (maTabName != r.GetString())
++        return false;
++
 +    return maSingleRef == r.GetSingleRef();
 +}
 +
 +// ============================================================================
 +
-+ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const ComplRefData& r ) :
++ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r ) :
 +    ScOpToken(ocExternalName, svDoubleRef),
 +    mnFileId(nFileId),
++    maTabName(rTabName),
 +    maDoubleRef(r)
 +{
 +}
@@ -1172,6 +2107,7 @@
 +ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) :
 +    ScOpToken(r), 
 +    mnFileId(r.mnFileId),
++    maTabName(r.maTabName),
 +    maDoubleRef(r.maDoubleRef)
 +{
 +}
@@ -1185,6 +2121,11 @@
 +    return mnFileId;
 +}
 +
++const String& ScExternalDoubleRefToken::GetString() const
++{
++    return maTabName;
++}
++
 +const ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() const
 +{
 +    return maDoubleRef;
@@ -1203,6 +2144,9 @@
 +    if (mnFileId != r.GetIndex())
 +        return false;
 +
++    if (maTabName != r.GetString())
++        return false;
++
 +    return maDoubleRef == r.GetDoubleRef();
 +}
 +
@@ -1261,7 +2205,7 @@
  
  short* ScJumpToken::GetJump() const                     { return pJump; }
  BOOL ScJumpToken::operator==( const ScToken& r ) const
-@@ -1893,6 +2067,11 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
+@@ -1893,6 +2171,21 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
      return Add( new ScMatrixToken( p ) );
  }
  
@@ -1270,51 +2214,341 @@
 +    return Add( new ScExternalNameToken(nFileId, rName) );
 +}
 +
++ScToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
++{
++    return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
++}
++
++ScToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef )
++{
++    return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
++}
++
  ScToken* ScTokenArray::AddColRowName( const SingleRefData& rRef )
  {
      return Add( new ScSingleRefOpToken( ocColRowName, rRef ) );
 diff --git sc/source/filter/excel/excform8.cxx sc/source/filter/excel/excform8.cxx
-index ebf8543..da9ded9 100644
+index ebf8543..e4968c2 100644
 --- sc/source/filter/excel/excform8.cxx
 +++ sc/source/filter/excel/excform8.cxx
-@@ -41,6 +41,7 @@
+@@ -41,6 +41,32 @@
  #include "xilink.hxx"
  #include "xiname.hxx"
  
 +#include "externalrefmgr.hxx"
++
++
++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;
++};
++
++}
  
  ExcelToSc8::ExcelToSc8( const XclImpRoot& rRoot ) :
      ExcelToSc( rRoot ),
-@@ -608,8 +609,22 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+@@ -53,15 +79,23 @@ ExcelToSc8::~ExcelToSc8()
+ {
+ }
+ 
+-
+-BOOL ExcelToSc8::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab )
++bool ExcelToSc8::GetExternalFileIdFromXti( UINT16 nIxti, sal_uInt16& rFileId ) const
+ {
+-	rFirstTab = rLastTab = 0;
++    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 );
++    return true;
++}
++
++bool ExcelToSc8::Read3DTabReference( SCTAB& rFirstTab, SCTAB& rLastTab, UINT16 nIxti )
++{
++	rFirstTab = rLastTab = 0;
++    return rLinkMan.GetScTabRange(rFirstTab, rLastTab, nIxti);
+ }
+ 
+ 
+@@ -608,8 +642,14 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
                      {
                          case xlExtName:
                          {
 -                            aStack << aPool.Store( ocNoName, pExtName->GetName() );
 -                            GetTracer().TraceFormulaExtName();
-+                            const String* pFileUrl = rLinkMan.GetSupbookUrl(nXtiIndex);
-+                            if (!pFileUrl)
-+                            {    
++                            sal_uInt16 nFileId;
++                            if (!GetExternalFileIdFromXti(nXtiIndex, nFileId))
++                            {
 +                                aStack << aPool.Store(ocNoName, pExtName->GetName());
 +                                break;
 +                            }
 +
-+                            String aFileUrl = ScGlobal::GetAbsDocName(*pFileUrl, GetDocShell());
-+                            ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
-+                            sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFileUrl);
-+                            fprintf(stdout, "ExcelToSc8::Convert:   external name (file: %s; name: %s; file id: %d)\n",
-+                                    rtl::OUStringToOString(aFileUrl, RTL_TEXTENCODING_UTF8).getStr(),
-+                                    rtl::OUStringToOString(pExtName->GetName(), RTL_TEXTENCODING_UTF8).getStr(),
-+                                    nFileId);
-+
 +                            aStack << aPool.StoreExtName(nFileId, pExtName->GetName());
                          }
                          break;
  
+@@ -657,47 +697,81 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+ 			case 0x7C:
+ 			case 0x3C: // Deleted 3-D Cell Reference			[    277]
+ 			{
+-				UINT16 nRw, nGrbitCol;
++                fprintf(stdout, "ExcelToSc8::Convert:   cell reference\n");
++				UINT16 nIxti, nRw, nGrbitCol;
+ 				SCTAB nTabFirst, nTabLast;
+ 
+-                BOOL bOK = Read3DTabReference( aIn, nTabFirst, nTabLast );
+-				aIn >> nRw >> nGrbitCol;
++                aIn >> nIxti >> nRw >> nGrbitCol;
+ 
+-				if( bOK )
+-				{
+-					aSRD.nTab = nTabFirst;
+-                    aSRD.SetFlag3D( TRUE );
+-					aSRD.SetTabRel( FALSE );
++                if (!Read3DTabReference(nTabFirst, nTabLast, nIxti))
++                {
++                    aPool << ocBad;
++                    aPool >> aStack;
++                    break;
++                }
+ 
+-                    ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
++                bool bExternal = !rLinkMan.IsSelfRef(nIxti);
++                fprintf(stdout, "ExcelToSc8::Convert:   first tab = %d; last tab = %d; external (%d)\n", nTabFirst, nTabLast, bExternal);
+ 
+-					switch ( nOp )
+-					{
+-						case 0x5C:
+-						case 0x7C:
+-						case 0x3C: // Deleted 3-D Cell Reference	[    277]
+-							// no information which part is deleted, set both
+-							aSRD.SetColDeleted( TRUE );
+-							aSRD.SetRowDeleted( TRUE );
+-					}
+-					if ( !ValidTab(nTabFirst) )
+-						aSRD.SetTabDeleted( TRUE );
++                aSRD.nTab = nTabFirst;
++                aSRD.SetFlag3D( TRUE );
++                aSRD.SetTabRel( FALSE );
+ 
+-					if( nTabLast != nTabFirst )
+-					{
+-						aCRD.Ref1 = aCRD.Ref2 = aSRD;
+-						aCRD.Ref2.nTab = nTabLast;
++                ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
++
++                switch ( nOp )
++                {
++                    case 0x5C:
++                    case 0x7C:
++                    case 0x3C: // Deleted 3-D Cell Reference	[    277]
++                        // no information which part is deleted, set both
++                        aSRD.SetColDeleted( TRUE );
++                        aSRD.SetRowDeleted( TRUE );
++                }
++
++                if (bExternal)
++                {
++                    // nTabFirst and nTabLast are the indices of the refernced 
++                    // sheets in the SUPBOOK record, hence do not represent
++                    // the actual indices of the original sheets since the
++                    // SUPBOOK record only stores referenced sheets and skips
++                    // the ones that are not referenced.
++
++                    const String& rTabName = rLinkMan.GetSupbookTabName(nIxti, nTabFirst);
++                    fprintf(stdout, "ExcelToSc8::Convert:   tab name of first sheet = '%s'\n",
++                            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++                    sal_uInt16 nFileId;
++                    if (!GetExternalFileIdFromXti(nIxti, nFileId))
++                    {
++                        aPool << ocBad;
++                        aPool >> aStack;
++                        break;
++                    }
++                    if (nTabLast != nTabFirst)
++                    {
++                        aCRD.Ref1 = aCRD.Ref2 = aSRD;
++                        aCRD.Ref2.nTab = nTabLast;
++                        aStack << aPool.StoreExtRef(nFileId, rTabName, aCRD);
++                    }
++                    else
++                        aStack << aPool.StoreExtRef(nFileId, rTabName, aSRD);
++                }
++                else
++                {
++                    if ( !ValidTab(nTabFirst))
++                        aSRD.SetTabDeleted( TRUE );
++
++                    if( nTabLast != nTabFirst )
++                    {
++                        aCRD.Ref1 = aCRD.Ref2 = aSRD;
++                        aCRD.Ref2.nTab = nTabLast;
+                         aCRD.Ref2.SetTabDeleted( !ValidTab(nTabLast) );
+-						aStack << aPool.Store( aCRD );
+-					}
+-					else
+-						aStack << aPool.Store( aSRD );
+-				}
+-				else
+-				{
+-					aPool << ocBad;
+-					aPool >> aStack;
+-				}
++                        aStack << aPool.Store( aCRD );
++                    }
++                    else
++                        aStack << aPool.Store( aSRD );
++                }
+ 			}
+ 				break;
+ 			case 0x5B:
+@@ -707,55 +781,75 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+ 			case 0x7D:
+ 			case 0x3D: // Deleted 3-D Area Reference			[    277]
+ 			{
+-				UINT16 nRw1, nGrbitCol1, nRw2, nGrbitCol2;
++                fprintf(stdout, "ExcelToSc8::Convert:   area reference\n");
++				UINT16 nIxti, nRw1, nGrbitCol1, nRw2, nGrbitCol2;
+ 				SCTAB nTabFirst, nTabLast;
++				aIn >> nIxti >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2;
+ 
+-                BOOL bOK = Read3DTabReference( aIn, nTabFirst, nTabLast );
+-				aIn >> nRw1 >> nRw2 >> nGrbitCol1 >> nGrbitCol2;
+-
+-				if( bOK )
++                if (!Read3DTabReference(nTabFirst, nTabLast, nIxti))
+ 				{
+-					SingleRefData	&rR1 = aCRD.Ref1;
+-					SingleRefData	&rR2 = aCRD.Ref2;
++					aPool << ocBad;
++					aPool >> aStack;
++                    break;
++				}
+ 
+-					rR1.nTab = nTabFirst;
+-					rR2.nTab = nTabLast;
+-                    rR1.SetFlag3D( TRUE );
+-					rR1.SetTabRel( FALSE );
+-                    rR2.SetFlag3D( nTabFirst != nTabLast );
+-					rR2.SetTabRel( FALSE );
++                bool bExternal = !rLinkMan.IsSelfRef(nIxti);
++                fprintf(stdout, "ExcelToSc8::Convert:   first tab = %d; last tab = %d; external (%d)\n", nTabFirst, nTabLast, bExternal);
++                
++                SingleRefData	&rR1 = aCRD.Ref1;
++                SingleRefData	&rR2 = aCRD.Ref2;
+ 
+-                    ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
+-                    ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
++                rR1.nTab = nTabFirst;
++                rR2.nTab = nTabLast;
++                rR1.SetFlag3D( TRUE );
++                rR1.SetTabRel( FALSE );
++                rR2.SetFlag3D( nTabFirst != nTabLast );
++                rR2.SetTabRel( FALSE );
+ 
+-					if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
+-						SetComplCol( aCRD );
+-					else if( IsComplRowRange( nRw1, nRw2 ) )
+-						SetComplRow( aCRD );
++                ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
++                ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
+ 
+-					switch ( nOp )
+-					{
+-						case 0x5D:
+-						case 0x7D:
+-						case 0x3D: // Deleted 3-D Area Reference	[    277]
+-							// no information which part is deleted, set all
+-							rR1.SetColDeleted( TRUE );
+-							rR1.SetRowDeleted( TRUE );
+-							rR2.SetColDeleted( TRUE );
+-							rR2.SetRowDeleted( TRUE );
+-					}
+-					if ( !ValidTab(nTabFirst) )
+-						rR1.SetTabDeleted( TRUE );
+-					if ( !ValidTab(nTabLast) )
+-						rR2.SetTabDeleted( TRUE );
++                if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
++                    SetComplCol( aCRD );
++                else if( IsComplRowRange( nRw1, nRw2 ) )
++                    SetComplRow( aCRD );
+ 
+-					aStack << aPool.Store( aCRD );
+-				}
+-				else
+-				{
+-					aPool << ocBad;
+-					aPool >> aStack;
+-				}
++                switch ( nOp )
++                {
++                    case 0x5D:
++                    case 0x7D:
++                    case 0x3D: // Deleted 3-D Area Reference	[    277]
++                        // no information which part is deleted, set all
++                        rR1.SetColDeleted( TRUE );
++                        rR1.SetRowDeleted( TRUE );
++                        rR2.SetColDeleted( TRUE );
++                        rR2.SetRowDeleted( TRUE );
++                }
++
++                if (bExternal)
++                {
++                    const String& rTabName = rLinkMan.GetSupbookTabName(nIxti, nTabFirst);
++                    fprintf(stdout, "ExcelToSc8::Convert:   tab name of first sheet = '%s'\n",
++                            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++                    sal_uInt16 nFileId;
++                    if (!GetExternalFileIdFromXti(nIxti, nFileId))
++                    {
++                        aPool << ocBad;
++                        aPool >> aStack;
++                        break;
++                    }
++                    aStack << aPool.StoreExtRef(nFileId, rTabName, aCRD);
++                }
++                else
++                {
++                    if ( !ValidTab(nTabFirst) )
++                        rR1.SetTabDeleted( TRUE );
++                    if ( !ValidTab(nTabLast) )
++                        rR2.SetTabDeleted( TRUE );
++    
++                    aStack << aPool.Store( aCRD );
++                }
+ 			}
+ 				break;
+ 			default: bError = TRUE;
 diff --git sc/source/filter/excel/tokstack.cxx sc/source/filter/excel/tokstack.cxx
-index 20ada63..821a4ad 100644
+index 20ada63..9c4ddba 100644
 --- sc/source/filter/excel/tokstack.cxx
 +++ sc/source/filter/excel/tokstack.cxx
-@@ -395,6 +395,16 @@ void TokenPool::GetElement( const UINT16 nId )
+@@ -395,6 +395,34 @@ void TokenPool::GetElement( const UINT16 nId )
                          pScToken->AddMatrix( p );
                  }
                  break;
@@ -1327,11 +2561,29 @@
 +                    pScToken->AddExternalName(r.mnFileId, r.maName);
 +                }
 +            }
++            case T_ExtRefC:
++            {
++                UINT16 n = pElement[nId];
++                if (n < maExtCellRefs.size())
++                {
++                    const ExtCellRef& r = maExtCellRefs[n];
++                    pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef);
++                }
++            }
++            case T_ExtRefA:
++            {
++                UINT16 n = pElement[nId];
++                if (n < maExtAreaRefs.size())
++                {
++                    const ExtAreaRef& r = maExtAreaRefs[n];
++                    pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef);
++                }
++            }
 +            break;
  			default:
  				DBG_ERROR("-TokenPool::GetElement(): Zustand undefiniert!?");
  		}
-@@ -477,6 +487,16 @@ void TokenPool::GetElementRek( const UINT16 nId )
+@@ -477,6 +505,34 @@ void TokenPool::GetElementRek( const UINT16 nId )
                              pScToken->AddMatrix( p );
                      }
                      break;
@@ -1344,11 +2596,29 @@
 +                        pScToken->AddExternalName(r.mnFileId, r.maName);
 +                    }
 +                }
++                case T_ExtRefC:
++                {
++                    UINT16 n = pElement[*pAkt];
++                    if (n < maExtCellRefs.size())
++                    {
++                        const ExtCellRef& r = maExtCellRefs[n];
++                        pScToken->AddExternalSingleReference(r.mnFileId, r.maTabName, r.maRef);
++                    }
++                }
++                case T_ExtRefA:
++                {
++                    UINT16 n = pElement[*pAkt];
++                    if (n < maExtAreaRefs.size())
++                    {
++                        const ExtAreaRef& r = maExtAreaRefs[n];
++                        pScToken->AddExternalDoubleReference(r.mnFileId, r.maTabName, r.maRef);
++                    }
++                }
 +                break;
  				default:
  					DBG_ERROR("-TokenPool::GetElementRek(): Zustand undefiniert!?");
  			}
-@@ -724,9 +744,28 @@ const TokenId TokenPool::StoreMatrix( SCSIZE nC, SCSIZE nR )
+@@ -724,9 +780,68 @@ const TokenId TokenPool::StoreMatrix( SCSIZE nC, SCSIZE nR )
      return ( const TokenId ) nElementAkt;
  }
  
@@ -1370,15 +2640,55 @@
 +    return static_cast<const TokenId>(nElementAkt);
 +}
 +
++const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
++{
++    if ( nElementAkt >= nElement )
++        GrowElement();
++
++    pElement[nElementAkt] = static_cast<UINT16>(maExtCellRefs.size());
++    pType[nElementAkt] = T_ExtRefC;
++    
++    maExtCellRefs.push_back(ExtCellRef());
++    ExtCellRef& r = maExtCellRefs.back();
++    r.mnFileId = nFileId;
++    r.maTabName = rTabName;
++    r.maRef = rRef;
++
++    ++nElementAkt;
++
++    return static_cast<const TokenId>(nElementAkt);
++}
++
++const TokenId TokenPool::StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef )
++{
++    if ( nElementAkt >= nElement )
++        GrowElement();
++
++    pElement[nElementAkt] = static_cast<UINT16>(maExtAreaRefs.size());
++    pType[nElementAkt] = T_ExtRefA;
++    
++    maExtAreaRefs.push_back(ExtAreaRef());
++    ExtAreaRef& r = maExtAreaRefs.back();
++    r.mnFileId = nFileId;
++    r.maTabName = rTabName;
++    r.maRef = rRef;
++
++    ++nElementAkt;
++
++    return static_cast<const TokenId>(nElementAkt);
++}
++
  void TokenPool::Reset( void )
  {
      nP_IdAkt = nP_IdLast = nElementAkt = nP_StrAkt = nP_DblAkt = nP_ErrAkt = nP_RefTrAkt = nP_ExtAkt = nP_NlfAkt = nP_MatrixAkt = 0;
 +    maExtNames.clear();
++    maExtCellRefs.clear();
++    maExtAreaRefs.clear();
  }
  
  
 diff --git sc/source/filter/excel/xeformula.cxx sc/source/filter/excel/xeformula.cxx
-index 3db8da7..97692bc 100644
+index 3db8da7..65a5775 100644
 --- sc/source/filter/excel/xeformula.cxx
 +++ sc/source/filter/excel/xeformula.cxx
 @@ -42,6 +42,12 @@
@@ -1394,7 +2704,40 @@
  // External reference log =====================================================
  
  XclExpRefLogEntry::XclExpRefLogEntry() :
-@@ -299,6 +305,7 @@ private:
+@@ -225,6 +231,32 @@ void XclExpFuncData::IncExpParamClassIdx()
+         ++mnClassIdx;
+ }
+ 
++// reference handling ---------------------------------------------------------
++
++namespace {
++
++inline bool lclIsRefRel2D( const SingleRefData& rRefData )
++{
++    return rRefData.IsColRel() || rRefData.IsRowRel();
++}
++
++inline bool lclIsRefDel2D( const SingleRefData& rRefData )
++{
++    return rRefData.IsColDeleted() || rRefData.IsRowDeleted();
++}
++
++inline bool lclIsRefRel2D( const ComplRefData& rRefData )
++{
++    return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 );
++}
++
++inline bool lclIsRefDel2D( const ComplRefData& rRefData )
++{
++    return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 );
++}
++
++} // namespace
++
+ // ----------------------------------------------------------------------------
+ 
+ /** Implementation class of the export formula compiler. */
+@@ -299,6 +331,7 @@ private:
      void                ProcessBoolean( const XclExpTokenData& rTokData );
      void                ProcessDdeLink( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
      void                ProcessExternal( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
@@ -1402,7 +2745,7 @@
  
      void                ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
      void                PrepareFunction( XclExpFuncData& rFuncData );
-@@ -1114,6 +1121,12 @@ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8
+@@ -1114,6 +1147,12 @@ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8
      StackVar eTokType = aTokData.GetType();
      OpCode eOpCode = aTokData.GetOpCode();
  
@@ -1415,7 +2758,7 @@
      switch( eTokType )
      {
          case svUnknown:     mbOk = false;                           break;
-@@ -1248,6 +1261,66 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
+@@ -1248,6 +1287,107 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
          ProcessFunction( rTokData, nExpClass );
  }
  
@@ -1430,11 +2773,50 @@
 +        case svSingleRef:
 +        {
 +            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svSingleRef not supported yet\n");
++            if (!mpScBasePos)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++            SingleRefData aRef(rTokData.mpScToken->GetSingleRef());
++            aRef.CalcAbsIfRel(*mpScBasePos);
++            ScToken* p = pRefMgr->getSingleRefToken(nFileId, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab), NULL);
++            if (!p)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++
++            mpLinkMgr->StoreCell(nFileId, rTokData.mpScToken->GetString(), 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());
++            sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
++            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>(nFirstSBTab));
++            }
++            AppendAddress(aXclPos);
 +        }
 +        break;
 +        case svDoubleRef:
 +        {
 +            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svDoubleRef not supported yet\n");
++            if (!mpScBasePos)
++            {
++                AppendErrorToken(XclTools::GetXclErrorCode(errNoRef), rTokData.mnSpaces);
++                break;
++            }
++            AppendBoolToken(true, rTokData.mnSpaces);
 +        }
 +        break;
 +        case svExternalName:
@@ -1449,6 +2831,8 @@
 +                break;
 +            }
 +
++            // Go through all these tokens to store the external cell/range 
++            // references for CRN records.
 +            for (ScToken* p = pArray->First(); p; p = pArray->Next())
 +            {
 +                if (p->GetOpCode() == ocExternalName)
@@ -1457,13 +2841,13 @@
 +                    {
 +                        SingleRefData aData(p->GetSingleRef());
 +                        aData.CalcAbsIfRel(*mpScBasePos);
-+                        mpLinkMgr->StoreCell(nFileId, aData);
++                        mpLinkMgr->StoreCell(nFileId, p->GetString(), aData);
 +                    }
 +                    else if (p->GetType() == svDoubleRef)
 +                    {
 +                        ComplRefData aData(p->GetDoubleRef());
 +                        aData.CalcAbsIfRel(*mpScBasePos);
-+                        mpLinkMgr->StoreCellRange(nFileId, aData);
++                        mpLinkMgr->StoreCellRange(nFileId, p->GetString(), aData);
 +                    }
 +                }
 +            }
@@ -1482,8 +2866,41 @@
  void XclExpFmlaCompImpl::ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
  {
      OpCode eOpCode = rTokData.GetOpCode();
+@@ -1623,32 +1763,6 @@ void XclExpFmlaCompImpl::AppendTrailingParam( XclExpFuncData& rFuncData )
+     }
+ }
+ 
+-// reference handling ---------------------------------------------------------
+-
+-namespace {
+-
+-inline bool lclIsRefRel2D( const SingleRefData& rRefData )
+-{
+-    return rRefData.IsColRel() || rRefData.IsRowRel();
+-}
+-
+-inline bool lclIsRefDel2D( const SingleRefData& rRefData )
+-{
+-    return rRefData.IsColDeleted() || rRefData.IsRowDeleted();
+-}
+-
+-inline bool lclIsRefRel2D( const ComplRefData& rRefData )
+-{
+-    return lclIsRefRel2D( rRefData.Ref1 ) || lclIsRefRel2D( rRefData.Ref2 );
+-}
+-
+-inline bool lclIsRefDel2D( const ComplRefData& rRefData )
+-{
+-    return lclIsRefDel2D( rRefData.Ref1 ) || lclIsRefDel2D( rRefData.Ref2 );
+-}
+-
+-} // namespace
+-
+ // ----------------------------------------------------------------------------
+ 
+ SCTAB XclExpFmlaCompImpl::GetScTab( const SingleRefData& rRefData ) const
 diff --git sc/source/filter/excel/xelink.cxx sc/source/filter/excel/xelink.cxx
-index b1bacad..2b54a89 100644
+index b1bacad..ebd2999 100644
 --- sc/source/filter/excel/xelink.cxx
 +++ sc/source/filter/excel/xelink.cxx
 @@ -38,6 +38,15 @@
@@ -1569,13 +2986,13 @@
      /** Stores all cells in the given range in a CRN record list. */
      void                StoreCellRange( const ScRange& rRange );
  
-+    void                StoreCell( sal_uInt16 nFileId, const ScAddress& rCell );
-+    void                StoreCellRange( sal_uInt16 nFileId, const ScRange& rRange );
++    void                StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell );
++    void                StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange );
 +
      /** 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,22 @@ public:
+@@ -407,9 +447,25 @@ public:
                              sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem );
  
@@ -1583,6 +3000,9 @@
 +                            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,
++                                XclExpRefLogEntry* pRefLogEntry = NULL );
++
      /** Writes all SUPBOOK records with their sub records. */
      virtual void        Save( XclExpStream& rStrm );
  
@@ -1598,7 +3018,7 @@
  private:
      typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
      typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
-@@ -435,15 +488,6 @@ private:
+@@ -435,15 +491,6 @@ private:
      void                AddExtSupbook( SCTAB nScTab );
  
  private:
@@ -1614,17 +3034,25 @@
      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.
-@@ -467,6 +511,9 @@ public:
+@@ -464,9 +511,17 @@ 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, 
++                               XclExpRefLogEntry* pRefLogEntry ) = 0;
++
      /** Derived classes store all cells in the given range in a CRN record list. */
      virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0;
  
-+    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef ) = 0;
-+    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0;
++    virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef ) = 0;
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0;
 +
      /** 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 +523,10 @@ public:
+@@ -476,6 +531,10 @@ public:
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem ) = 0;
  
@@ -1635,12 +3063,19 @@
      /** Derived classes write the entire link table to the passed stream. */
      virtual void        Save( XclExpStream& rStrm ) = 0;
  
-@@ -499,13 +550,21 @@ public:
- 
+@@ -497,15 +556,28 @@ 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, 
++                               XclExpRefLogEntry* pRefLogEntry );
++
      virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
  
-+    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
-+    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 );
++    virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 );
 +
      virtual bool        InsertAddIn(
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
@@ -1657,12 +3092,19 @@
      virtual void        Save( XclExpStream& rStrm );
  
  private:
-@@ -552,13 +611,21 @@ public:
- 
+@@ -550,15 +622,28 @@ 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, 
++                               XclExpRefLogEntry* pRefLogEntry );
++
      virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
  
-+    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
-+    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 );
++    virtual void        StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 );
 +
      virtual bool        InsertAddIn(
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
@@ -1679,7 +3121,7 @@
      virtual void        Save( XclExpStream& rStrm );
  
  private:
-@@ -885,6 +952,94 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
+@@ -885,6 +970,94 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
          mxMatrix->Save( rStrm );
  }
  
@@ -1774,7 +3216,7 @@
  // List of external names =====================================================
  
  XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
-@@ -920,6 +1075,12 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde(
+@@ -920,6 +1093,12 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde(
      return nIndex;
  }
  
@@ -1787,7 +3229,7 @@
  void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
  {
      maNameList.Save( rStrm );
-@@ -1066,6 +1227,78 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
+@@ -1066,6 +1245,78 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
      maUsedCells.SetMultiMarkArea( rRange );
  }
  
@@ -1866,7 +3308,7 @@
  void XclExpXct::Save( XclExpStream& rStrm )
  {
      XclExpRecord::Save( rStrm );
-@@ -1206,6 +1439,41 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+@@ -1206,6 +1457,41 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
          xXct->StoreCellRange( GetRoot(), rRange );
  }
  
@@ -1908,7 +3350,7 @@
  sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName )
  {
      DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
-@@ -1226,6 +1494,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
+@@ -1226,6 +1512,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
      return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
  }
  
@@ -1920,7 +3362,7 @@
  void XclExpSupbook::Save( XclExpStream& rStrm )
  {
      // SUPBOOK record
-@@ -1352,6 +1625,131 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+@@ -1352,6 +1643,135 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
      }
  }
  
@@ -1944,7 +3386,7 @@
 +
 +}
 +
-+void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const ScAddress& rCell )
++void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell )
 +{
 +    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
 +    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
@@ -1959,16 +3401,17 @@
 +        nSupbookId = Append(xSupbook);
 +    }
 +
-+    ScToken* pToken = pRefMgr->getSingleRefToken(nFileId, rCell, NULL);
++    ScToken* pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL);
 +    if (!pToken)
 +        return;
 +
-+    const String* pTabName = pRefMgr->getExternalTableName(nFileId, rCell.Tab());
-+    if (!pTabName)
-+        return;
++//  const String* pTabName = pRefMgr->getExternalTableName(nFileId, rCell.Tab());
++//  if (!pTabName)
++//      return;
 +
-+    sal_uInt16 nSheetId = xSupbook->GetTabIndex(*pTabName);
++    sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
 +    FindSBIndexEntry f(nSupbookId, nSheetId);
++    fprintf(stdout, "XclExpSupbookBuffer::StoreCell: supbook id = %d; sheet id = %d\n", nSupbookId, nSheetId);
 +    XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
 +    XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
 +    if (itr == itrEnd)
@@ -1982,7 +3425,7 @@
 +    xSupbook->StoreCell(nSheetId, rCell, *pToken);
 +}
 +
-+void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const ScRange& rRange )
++void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange )
 +{
 +    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
 +    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
@@ -1998,11 +3441,12 @@
 +    }
 +
 +    SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
++    SCTAB nTabCount = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
 +
 +    // If this is a multi-table range, get token for each table.
 +    vector<ScToken*> aMatrixList;
-+    aMatrixList.reserve(nTab2 - nTab1 + 1);
-+    ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rRange, NULL);
++    aMatrixList.reserve(nTabCount);
++    ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
 +    if (!pArray)
 +        return;
 +
@@ -2018,22 +3462,24 @@
 +        }
 +    }
 +
-+    if (aMatrixList.size() != nTab2 - nTab1 + 1)
++    if (aMatrixList.size() != nTabCount)
 +    {
 +        // matrix size mis-match !
 +        return;
 +    }
 +
++    sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
++
 +    ScRange aRange(rRange);
 +    aRange.aStart.SetTab(0);
 +    aRange.aEnd.SetTab(0);
-+    for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
++    for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
 +    {
 +        const String* pTabName = pRefMgr->getExternalTableName(nFileId, nTab);
 +        if (!pTabName)
 +            continue;
 +
-+        sal_uInt16 nSheetId = xSupbook->GetTabIndex(*pTabName);
++        sal_uInt16 nSheetId = nFirstSheetId + static_cast<sal_uInt16>(nTab);
 +        FindSBIndexEntry f(nSupbookId, nSheetId);
 +        XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
 +        XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
@@ -2052,7 +3498,7 @@
  bool XclExpSupbookBuffer::InsertAddIn(
          sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1383,6 +1781,20 @@ bool XclExpSupbookBuffer::InsertDde(
+@@ -1383,6 +1803,72 @@ bool XclExpSupbookBuffer::InsertDde(
      return rnExtName > 0;
  }
  
@@ -2070,19 +3516,83 @@
 +    return rnExtName > 0;
 +}
 +
++XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
++                                       XclExpRefLogEntry* pRefLogEntry )
++{
++    XclExpXti aXti(0, EXC_NOTAB, EXC_NOTAB);
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++    if (!pUrl)
++        return aXti;
++
++    XclExpSupbookRef xSupbook;
++    sal_uInt16 nSupbookId;
++    if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
++    {
++        xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
++        nSupbookId = Append(xSupbook);
++    }
++    aXti.mnSupbook = nSupbookId;
++
++    for (sal_uInt16 nTab = nFirstXclTab; nTab <= nLastXclTab; ++nTab)
++    {
++        const String* pTabName = pRefMgr->getExternalTableName(nFileId, nTab);
++        if (!pTabName)
++            continue;
++
++        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);
++        if (itr == itrEnd)
++        {
++            maSBIndexVec.push_back(XclExpSBIndex());
++            XclExpSBIndex& r = maSBIndexVec.back();
++            r.mnSupbook = nSupbookId;
++            r.mnSBTab   = nSheetId;
++        }
++        if (nTab == nFirstXclTab)
++            aXti.mnFirstSBTab = nSheetId;
++        if (nTab == nLastXclTab)
++            aXti.mnLastSBTab = nSheetId;
++    }
++
++    if (pRefLogEntry)
++    {
++        pRefLogEntry->mnFirstXclTab = nFirstXclTab;
++        pRefLogEntry->mnLastXclTab  = nLastXclTab;
++        if (xSupbook.is())
++            xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
++    }
++
++    return aXti;
++}
++
  void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
  {
      maSupbookList.Save( rStrm );
-@@ -1490,6 +1902,16 @@ void XclExpLinkManagerImpl5::StoreCellRange( const SingleRefData& /*rRef1*/, con
+@@ -1485,11 +1971,28 @@ 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*/ )
++{
++    // not implemented
++}
++
+ void XclExpLinkManagerImpl5::StoreCellRange( const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
+ {
      // not implemented
  }
  
-+void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const SingleRefData& /*rRef*/ )
++void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef*/ )
 +{
 +    // not implemented
 +}
 +
-+void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
++void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
 +{
 +    // not implemented
 +}
@@ -2090,7 +3600,7 @@
  bool XclExpLinkManagerImpl5::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1510,6 +1932,14 @@ bool XclExpLinkManagerImpl5::InsertDde(
+@@ -1510,6 +2013,14 @@ bool XclExpLinkManagerImpl5::InsertDde(
      return false;
  }
  
@@ -2105,27 +3615,44 @@
  void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
  {
      if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
-@@ -1652,6 +2082,19 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
+@@ -1630,6 +2141,16 @@ 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 )
++{
++    XclExpXti aXti = maSBBuffer.GetXti(nFileId, nFirstXclTab, nLastXclTab, pRefLogEntry);
++    rnExtSheet = InsertXti(aXti);
++    rnFirstSBTab = aXti.mnFirstSBTab;
++    rnLastSBTab  = aXti.mnLastSBTab;
++}
++
+ 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
      }
  }
  
-+void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef )
++void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
 +{
 +    ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
-+    maSBBuffer.StoreCell(nFileId, aAddr);
++    maSBBuffer.StoreCell(nFileId, rTabName, aAddr);
 +}
 +
-+void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 )
++void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef1, const SingleRefData& rRef2 )
 +{
 +    ScRange aRange(static_cast<SCCOL>(rRef1.nCol), static_cast<SCROW>(rRef1.nRow), static_cast<SCTAB>(rRef1.nTab),
 +                   static_cast<SCCOL>(rRef2.nCol), static_cast<SCROW>(rRef2.nRow), static_cast<SCTAB>(rRef2.nTab));
-+    maSBBuffer.StoreCellRange(nFileId, aRange);
++    maSBBuffer.StoreCellRange(nFileId, rTabName, aRange);
 +}
 +
  bool XclExpLinkManagerImpl8::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1677,6 +2120,18 @@ bool XclExpLinkManagerImpl8::InsertDde(
+@@ -1677,6 +2211,18 @@ bool XclExpLinkManagerImpl8::InsertDde(
      return false;
  }
  
@@ -2144,24 +3671,39 @@
  void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
  {
      if( !maXtiVec.empty() )
-@@ -1755,6 +2210,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
+@@ -1745,6 +2291,14 @@ 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, 
++                                      XclExpRefLogEntry* pRefLogEntry )
++{
++    mxImpl->FindExtSheet( nFileId, rnExtSheet, rnFirstSBTab, rnLastSBTab, nFirstXclTab, nLastXclTab, pRefLogEntry );
++}
++
+ void XclExpLinkManager::StoreCell( const SingleRefData& rRef )
+ {
+     mxImpl->StoreCellRange( rRef, rRef );
+@@ -1755,6 +2309,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
      mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
  }
  
-+void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef )
++void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
 +{
-+    mxImpl->StoreCell( nFileId, rRef );
++    mxImpl->StoreCell( nFileId, rTabName, rRef );
 +}
 +
-+void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const ComplRefData& rRef )
++void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef )
 +{
-+    mxImpl->StoreCellRange( nFileId, rRef.Ref1, rRef.Ref2 );
++    mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 );
 +}
 +
  bool XclExpLinkManager::InsertAddIn(
          sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
  {
-@@ -1768,6 +2233,13 @@ bool XclExpLinkManager::InsertDde(
+@@ -1768,6 +2332,13 @@ bool XclExpLinkManager::InsertDde(
      return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
  }
  
@@ -2176,10 +3718,97 @@
  {
      mxImpl->Save( rStrm );
 diff --git sc/source/filter/excel/xilink.cxx sc/source/filter/excel/xilink.cxx
-index 01932a5..b20849e 100644
+index 01932a5..38b846b 100644
 --- sc/source/filter/excel/xilink.cxx
 +++ sc/source/filter/excel/xilink.cxx
-@@ -191,6 +191,11 @@ public:
+@@ -39,6 +39,31 @@
+ #include "xihelper.hxx"
+ #include "xiname.hxx"
+ 
++
++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 ***
+ // ============================================================================
+@@ -52,8 +77,10 @@ public:
+     /** Reads a cached value and stores it with its cell address. */
+     explicit            XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+ 
++#if 0
+     /** Copies the cached value to sheet nTab in the document. */
+     void                SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const;
++#endif
+ 
+ private:
+     XclAddress          maXclPos;       /// Excel position of the cached cell.
+@@ -76,11 +103,13 @@ public:
+     /** Reads a CRN record (external referenced cell) at the specified address. */
+     void                ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+ 
++#if 0
+     /** Creates a new linked table in the passed document and fills it with the cached cells.
+         @descr  Stores the index of the new sheet, will be accessible with GetScTab(). */
+     void                CreateAndFillTable(
+                             const XclImpRoot& rRoot, const String& rAbsUrl,
+                             const String& rFilterName, const String& rFilterOpt );
++#endif
+ 
+ private:
+     typedef ScfDelList< XclImpCrn > XclImpCrnList;
+@@ -112,11 +141,13 @@ public:
+ 
+     /** Returns the URL of the external document. */
+     inline const String& GetXclUrl() const { return maXclUrl; }
+-
++#if 0
+     /** Returns Calc sheet index from Excel sheet index. */
+     SCTAB               GetScTabNum( sal_uInt16 nXclTab ) const;
+     /** Returns Calc sheet index from sheet name. */
+     SCTAB               GetScTabNum( const String& rTabName ) const;
++#endif
++    sal_uInt16          GetXclTabNum( const String& rTabName ) const;
+ 
+     /** 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:
+     /** 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;
++
++#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
+ 
+ private:
+     typedef ScfDelList< XclImpSupbookTab >  XclImpSupbookTabList;
+@@ -191,6 +226,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;
@@ -2188,10 +3817,155 @@
 +        the index. */
 +    const String*       GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
 +
++    const String&       GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
++
      /** 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.
-@@ -584,6 +589,14 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex,
+@@ -198,19 +240,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;
+-
++#if 0
+     /** Returns the Calc sheet index of a table in an external document.
+         @return  Calc sheet index or EXC_TAB_INVALID on error. */
+     SCTAB               GetScTab( const String& rUrl, const String& rTabName ) const;
++#endif
++    sal_uInt16          GetXclTab( const String& rUrl, const String& rTabName ) const;
+ 
+ private:
+     /** Returns the specified SUPBOOK (external document). */
+     const XclImpSupbook* GetSupbook( sal_uInt32 nXtiIndex ) const;
+     /** Returns the SUPBOOK (external workbook) specified by its URL. */
+     const XclImpSupbook* GetSupbook( const String& rUrl ) const;
+-
++#if 0
+     /** Creates all external sheets in the Calc document. */
+     void                CreateTables();
++#endif
++    void                LoadCachedValues();
+ 
+     /** 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 ) :
+ {
+ }
+ 
++#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
+         }
+     }
+ }
++#endif
+ 
+ // Sheet in an external document ==============================================
+ 
+@@ -383,6 +431,7 @@ void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
+     maCrnList.Append( new XclImpCrn( rStrm, rXclPos ) );
+ }
+ 
++#if 0
+ 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,
+             for( const XclImpCrn* pCrn = maCrnList.First(); pCrn; pCrn = maCrnList.Next() )
+                 pCrn->SetCell( rRoot, mnScTab );
+ }
++#endif
+ 
+ // External document (SUPBOOK) ================================================
+ 
+@@ -457,13 +507,14 @@ void XclImpSupbook::ReadExternname( XclImpStream& rStrm )
+ {
+     maExtNameList.Append( new XclImpExtName( rStrm, meType == EXC_SBTYPE_ADDIN ) );
+ }
+-
++#if 0
+ SCTAB XclImpSupbook::GetScTabNum( sal_uInt16 nXclTab ) const
+ {
+     if( meType == EXC_SBTYPE_SELF )
+         return static_cast< SCTAB >( nXclTab );
+-    const XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( nXclTab );
+-    return pSBTab ? pSBTab->GetScTab() : SCTAB_INVALID;
++    return SCTAB_INVALID;
++//  const XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( nXclTab );
++//  return pSBTab ? pSBTab->GetScTab() : SCTAB_INVALID;
+ }
+ 
+ SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
+@@ -473,6 +524,15 @@ SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
+             return pSBTab->GetScTab();
+     return SCTAB_INVALID;
+ }
++#endif
++sal_uInt16 XclImpSupbook::GetXclTabNum( const String& rTabName ) const
++{
++    sal_uInt16 nTabNum = 0;
++    for (const XclImpSupbookTab* pSBTab = maSupbTabList.First(); pSBTab; pSBTab = maSupbTabList.Next(), ++nTabNum)
++        if (pSBTab->GetTabName() == rTabName)
++            return nTabNum;
++    return EXC_NOTAB;
++}
+ 
+ const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
+ {
+@@ -492,6 +552,22 @@ const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
+     return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
+ }
+ 
++const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
++{
++    if (maSupbTabList.Empty())
++        return EMPTY_STRING;
++
++    sal_uInt16 i = 0;
++    for (XclImpSupbookTab* p = maSupbTabList.First(); p; p = maSupbTabList.Next(), ++i)
++    {
++        if (i == nXtiTab)
++            return p->GetTabName();
++    }
++
++    return EMPTY_STRING;
++}
++
++#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
+                 pSBTab->CreateAndFillTable( GetRoot(), aAbsUrl, maFilterName, maFilterOpt );
+     }
+ }
++#endif
+ 
+ // Import link manager ========================================================
+ 
+@@ -531,7 +608,7 @@ void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
+         --nXtiCount;
+     }
+ 
+-    CreateTables();
++    LoadCachedValues();
+ }
+ 
+ void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
+@@ -570,8 +647,8 @@ bool XclImpLinkManagerImpl::GetScTabRange(
+     {
+         if( const XclImpSupbook* pSupbook = maSupbookList.GetObject( pXti->mnSupbook ) )
+         {
+-            rnFirstScTab = pSupbook->GetScTabNum( pXti->mnSBTabFirst );
+-            rnLastScTab = pSupbook->GetScTabNum( pXti->mnSBTabLast );
++            rnFirstScTab = pXti->mnSBTabFirst;
++            rnLastScTab  = pXti->mnSBTabLast;
+             return true;
+         }
+     }
+@@ -584,6 +661,20 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex,
      return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
  }
  
@@ -2203,10 +3977,60 @@
 +    return &p->GetXclUrl();
 +}
 +
- bool XclImpLinkManagerImpl::GetLinkData( String& rApplic, String& rTopic, sal_uInt16 nXtiIndex ) const
- {
-     const XclImpSupbook* pSupbook = GetSupbook( nXtiIndex );
-@@ -707,6 +720,11 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal
++const String& XclImpLinkManagerImpl::GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const
++{
++    const XclImpSupbook* p = GetSupbook(nXti);
++    return p ? p->GetTabName(nXtiTab) : EMPTY_STRING;
++}
++
+ 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
+     const XclImpSupbook* pSupbook = GetSupbook( nExtSheet );
+     return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
+ }
+-
++#if 0
+ SCTAB XclImpLinkManagerImpl::GetScTab( const String& rUrl, const String& rTabName ) const
+ {
+     const XclImpSupbook* pSupbook = GetSupbook( rUrl );
+     return pSupbook ? pSupbook->GetScTabNum( rTabName ) : SCTAB_INVALID;
+ }
++#endif
++sal_uInt16 XclImpLinkManagerImpl::GetXclTab( const String& rUrl, const String& rTabName ) const
++{
++    const XclImpSupbook* pSupbook = GetSupbook( rUrl );
++    return pSupbook ? pSupbook->GetXclTabNum( rTabName ) : EXC_NOTAB;
++}
+ 
+ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt32 nXtiIndex ) const
+ {
+@@ -616,6 +713,7 @@ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) con
+     return 0;
+ }
+ 
++#if 0
+ void XclImpLinkManagerImpl::CreateTables()
+ {
+     DBG_ASSERT( !mbCreated, "XclImpLinkManager::CreateTables - multiple call" );
+@@ -637,6 +735,15 @@ void XclImpLinkManagerImpl::CreateTables()
+     }
+     mbCreated = true;
+ }
++#endif
++
++void 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.
++}
+ 
+ bool XclImpLinkManagerImpl::FindNextTabRange(
+         sal_uInt16& rnSBTabFirst, sal_uInt16& rnSBTabLast,
+@@ -707,6 +814,16 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal
      return mxImpl->GetExternName( nXtiIndex, nExtName );
  }
  
@@ -2215,11 +4039,76 @@
 +    return mxImpl->GetSupbookUrl(nXtiIndex);
 +}
 +
++const String& XclImpLinkManager::GetSupbookTabName( sal_uInt16 nXti,  sal_uInt16 nXtiTab ) const
++{
++    return mxImpl->GetSupbookTabName(nXti, nXtiTab);
++}
++
  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
+ {
+     return mxImpl->GetMacroName( nExtSheet, nExtName );
+ }
+-
++#if 0
+ SCTAB XclImpLinkManager::GetScTab( const String& rUrl, const String& rTabName ) const
+ {
+     return mxImpl->GetScTab( rUrl, rTabName );
+ }
++#endif
++sal_uInt16 XclImpLinkManager::GetXclTab( const String& rUrl, const String& rTabName ) const
++{
++    return mxImpl->GetXclTab( rUrl, rTabName );
++}
+ 
+ // ============================================================================
+ 
+diff --git sc/source/filter/inc/XclImpChangeTrack.hxx sc/source/filter/inc/XclImpChangeTrack.hxx
+index 2335c6c..399a650 100644
+--- sc/source/filter/inc/XclImpChangeTrack.hxx
++++ sc/source/filter/inc/XclImpChangeTrack.hxx
+@@ -182,7 +182,7 @@ class XclImpChTrFmlConverter : public ExcelToSc8
+ private:
+ 	XclImpChangeTrack&			rChangeTrack;
+ 
+-    virtual BOOL                Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab );
++    virtual bool                Read3DTabReference( SCTAB& rFirstTab, SCTAB& rLastTab, UINT16 nIxti );
+ 
+ public:
+ 	inline						XclImpChTrFmlConverter(
+diff --git sc/source/filter/inc/excform.hxx sc/source/filter/inc/excform.hxx
+index 915dd98..6913b25 100644
+--- sc/source/filter/inc/excform.hxx
++++ sc/source/filter/inc/excform.hxx
+@@ -113,8 +113,9 @@ private:
+     void                ExcRelToScRel8( UINT16 nRow, UINT16 nCol, SingleRefData&,
+ 							const BOOL bName );
+ 
+-						// this function must read 2 bytes from stream and adjust <nBytesLeft>
+-    virtual BOOL        Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab );
++    bool                GetExternalFileIdFromXti( UINT16 nIxti, sal_uInt16& rFileId ) const;
++
++    virtual bool        Read3DTabReference( SCTAB& rFirstTab, SCTAB& rLastTab, UINT16 nIxti );
+ 
+ public:
+                         ExcelToSc8( const XclImpRoot& rRoot );
+diff --git sc/source/filter/inc/fdumper.hxx sc/source/filter/inc/fdumper.hxx
+index aea8de6..8f57403 100644
+--- sc/source/filter/inc/fdumper.hxx
++++ sc/source/filter/inc/fdumper.hxx
+@@ -31,7 +31,7 @@
+ #ifndef SC_FDUMPER_HXX
+ #define SC_FDUMPER_HXX
+ 
+-#define SCF_INCL_DUMPER (OSL_DEBUG_LEVEL > 0)
++#define SCF_INCL_DUMPER (OSL_DEBUG_LEVEL > 0) && 0
+ 
+ #include <map>
+ #include <math.h>
 diff --git sc/source/filter/inc/tokstack.hxx sc/source/filter/inc/tokstack.hxx
-index 89e955a..02429d3 100644
+index 89e955a..5bb6772 100644
 --- sc/source/filter/inc/tokstack.hxx
 +++ sc/source/filter/inc/tokstack.hxx
 @@ -35,6 +35,8 @@
@@ -2231,15 +4120,17 @@
  
  typedef OpCode DefTokenId;
  // in PRODUCT version: ambiguity between OpCode (being USHORT) and UINT16
-@@ -78,6 +80,7 @@ enum E_TYPE
+@@ -78,6 +80,9 @@ enum E_TYPE
  	T_Ext,		// irgendwas Unbekanntes mit Funktionsnamen
  	T_Nlf,		// token for natural language formula
  	T_Matrix,	// token for inline arrays
 +    T_ExtName,  // token for external names
++    T_ExtRefC,
++    T_ExtRefA,
  	T_Error		// fuer Abfrage im Fehlerfall
  };
  
-@@ -134,6 +137,14 @@ class TokenPool
+@@ -134,6 +139,32 @@ class TokenPool
  		UINT16						nP_Matrix;
  		UINT16						nP_MatrixAkt;
  
@@ -2251,33 +4142,91 @@
 +        };
 +        ::std::vector<ExtName>      maExtNames;
 +
++        /** for storage of external cell references */
++        struct ExtCellRef
++        {
++            sal_uInt16      mnFileId;
++			String			maTabName;
++            SingleRefData   maRef;
++        };
++        ::std::vector<ExtCellRef>   maExtCellRefs;
++
++        /** for storage of external area references */
++        struct ExtAreaRef
++        {
++            sal_uInt16      mnFileId;
++			String			maTabName;
++            ComplRefData    maRef;
++        };
++        ::std::vector<ExtAreaRef>   maExtAreaRefs;
++
  		UINT16*						pElement;	// Array mit Indizes fuer Elemente
  		E_TYPE*						pType;		// ...mit Typ-Info
  		UINT16*						pSize;		// ...mit Laengenangabe (Anz. UINT16)
-@@ -180,6 +191,7 @@ class TokenPool
+@@ -180,12 +211,14 @@ class TokenPool
  										// 4 externals (e.g. AddIns, Makros...)
  		const TokenId				StoreNlf( const SingleRefData& rTr );
  		const TokenId				StoreMatrix( SCSIZE nC, SCSIZE nR );
 +        const TokenId               StoreExtName( sal_uInt16 nFileId, const String& rName );
++        const TokenId               StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
++        const TokenId               StoreExtRef( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef );
  
  		inline const TokenId		LastId( void ) const;
  		inline const ScTokenArray*	operator []( const TokenId nId );
+ 		void						Reset( void );
+ 		inline E_TYPE				GetType( const TokenId& nId ) const;
+-		inline const SingleRefData*	GetSRD( const TokenId& nId ) const;
+ 		BOOL						IsSingleOp( const TokenId& nId, const DefTokenId eId ) const;
+         const String*               GetExternal( const TokenId& nId ) const;
+         const String*               GetString( const TokenId& nId ) const;
+@@ -374,21 +407,5 @@ inline E_TYPE TokenPool::GetType( const TokenId& rId ) const
+ }
+ 
+ 
+-inline const SingleRefData* TokenPool::GetSRD( const TokenId& rId ) const
+-{
+-    SingleRefData* pRet;
+-
+-	UINT16 nId = (UINT16) rId - 1;
+-
+-	if( nId < nElementAkt && pType[ nId ] == T_RefC )
+-		pRet = ppP_RefTr[ pElement[ nId ] ];
+-	else
+-		pRet = NULL;
+-
+-	return pRet;
+-}
+-
+-
+-
+ #endif
+ 
 diff --git sc/source/filter/inc/xelink.hxx sc/source/filter/inc/xelink.hxx
-index 795219c..2d528d9 100644
+index 795219c..53e864f 100644
 --- sc/source/filter/inc/xelink.hxx
 +++ sc/source/filter/inc/xelink.hxx
-@@ -178,6 +178,10 @@ public:
+@@ -173,11 +173,20 @@ 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, 
++                                      XclExpRefLogEntry* pRefLogEntry = NULL );
++
+     /** Stores the cell with the given address in a CRN record list. */
+     void                StoreCell( const SingleRefData& rRef );
      /** Stores all cells in the given range in a CRN record list. */
      void                StoreCellRange( const ComplRefData& rRef );
  
-+    void                StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
++    void                StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef );
 +
-+    void                StoreCellRange( sal_uInt16 nFileId, const ComplRefData& rRef );
++    void                StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef );
 +
      /** 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 +197,10 @@ public:
+@@ -193,6 +202,10 @@ public:
                              sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
                              const String& rApplic, const String& rTopic, const String& rItem );
  
@@ -2289,25 +4238,65 @@
      virtual void        Save( XclExpStream& rStrm );
  
 diff --git sc/source/filter/inc/xilink.hxx sc/source/filter/inc/xilink.hxx
-index 0d547fe..3c2d0d9 100644
+index 0d547fe..c9d7567 100644
 --- sc/source/filter/inc/xilink.hxx
 +++ sc/source/filter/inc/xilink.hxx
-@@ -179,6 +179,9 @@ public:
+@@ -179,6 +179,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;
 +
 +    const String* GetSupbookUrl( sal_uInt16 nXtiIndex ) const;
 +
++    const String& GetSupbookTabName( sal_uInt16 nXti, sal_uInt16 nXtiTab ) const;
++
      /** 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:
+     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;
+-
++#if 0
+     /** Returns the Calc sheet index of a table in an external document.
+         @return  Calc sheet index or EXC_TAB_INVALID on error. */
+     SCTAB               GetScTab( const String& rUrl, const String& rTabName ) const;
++#endif
++    sal_uInt16          GetXclTab( const String& rUrl,  const String& rTabName ) const;
+ 
+ private:
+     typedef ::std::auto_ptr< XclImpLinkManagerImpl > XclImpLinkMgrImplPtr;
+diff --git sc/source/filter/xcl97/XclImpChangeTrack.cxx sc/source/filter/xcl97/XclImpChangeTrack.cxx
+index 022b472..75cc8c6 100644
+--- sc/source/filter/xcl97/XclImpChangeTrack.cxx
++++ sc/source/filter/xcl97/XclImpChangeTrack.cxx
+@@ -176,7 +176,7 @@ sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab
+         // - sheet name, always separated from URL
+         String aTabName( pStrm->ReadUniString() );
+         pStrm->Ignore( 1 );
+-        rFirstTab = rLastTab = static_cast<SCTAB>(GetLinkManager().GetScTab( aUrl, aTabName ));
++        rFirstTab = rLastTab = static_cast<SCTAB>(GetLinkManager().GetXclTab( aUrl, aTabName ));
+ 	}
+ 	return sal_True;
+ }
+@@ -490,9 +490,8 @@ XclImpChTrFmlConverter::~XclImpChTrFmlConverter()
+ }
+ 
+ // virtual, called from ExcToSc8::Convert()
+-BOOL XclImpChTrFmlConverter::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab )
++bool XclImpChTrFmlConverter::Read3DTabReference( SCTAB& rFirstTab, SCTAB& rLastTab, UINT16 /*nIxti*/ )
+ {
+-    rStrm.Ignore( 2 );
+ 	return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab );
+ }
+ 
 diff --git sc/source/ui/docshell/externalrefmgr.cxx sc/source/ui/docshell/externalrefmgr.cxx
 new file mode 100644
-index 0000000..1e6da7c
+index 0000000..b1d4117
 --- /dev/null
 +++ sc/source/ui/docshell/externalrefmgr.cxx
-@@ -0,0 +1,795 @@
+@@ -0,0 +1,1115 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -2380,9 +4369,219 @@
 +using ::std::find;
 +using ::std::distance;
 +
-+#define SRCDOC_LIFE_SPAN     6000       // 1 minute (in 100th of sec)
++
++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;
++};
++
++}
++
++#define SRCDOC_LIFE_SPAN     6000       // 1 minute (in 100th of a sec)
 +#define SRCDOC_SCAN_INTERVAL 1000*2     // every 2 seconds (in msec)
 +
++// ============================================================================
++
++ScExternalRefCache::ScExternalRefCache()
++{
++}
++ScExternalRefCache::~ScExternalRefCache()
++{
++}
++
++ScToken* ScExternalRefCache::getCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::getCellData");
++
++    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++        // specified document is not cached.
++        return NULL;
++
++    DocItem& rDoc = itrDoc->second;
++    TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
++    if (itrTabId == rDoc.maTableNameIndex.end())
++        // 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.
++        return NULL;
++
++    return itrRow->second.get();
++}
++
++ScTokenArray* ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::getCellRangeData");
++
++    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++        // specified document is not cached.
++        return NULL;
++
++    DocItem& rDoc = itrDoc->second;
++    TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
++    if (itrTabId == rDoc.maTableNameIndex.end())
++        // the specified table is not in cache.
++        return NULL;
++
++    const ScAddress& s = rRange.aStart;
++    const ScAddress& e = rRange.aEnd;
++
++    SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
++    SCCOL nCol1 = s.Col(), nCol2 = e.Col();
++    SCROW nRow1 = s.Row(), nRow2 = e.Row();
++
++    // Make sure I have all the tables cached.
++    size_t nTabFirstId = itrTabId->second;
++    size_t nTabLastId  = nTabFirstId + nTab2 - nTab1;
++    if (nTabLastId >= rDoc.maTables.size())
++        // not all tables are cached.
++        return NULL;
++
++    auto_ptr<ScTokenArray> pArray(new ScTokenArray);
++    bool bFirstTab = true;
++    for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
++    {
++        TableDataTypeRef pTab = rDoc.maTables[nTab];
++
++        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.
++                    return NULL;
++
++                ScToken* pToken = itrRow->second.get();
++                SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
++                switch (pToken->GetType())
++                {
++                    case svDouble:
++                        xMat->PutDouble(pToken->GetDouble(), nC, nR);
++                    break;
++                    case svString:
++                        xMat->PutString(pToken->GetString(), nC, nR);
++                    break;
++                    default:
++                        xMat->PutEmpty(nC, nR);
++                }
++            }
++        }
++        if (!bFirstTab)
++            pArray->AddOpCode(ocSep);
++
++        ScMatrix* pMat2 = xMat;
++        ScMatrixToken aToken(pMat2);
++        pArray->AddToken(aToken);
++
++        bFirstTab = false;
++    }
++    return pArray.release();
++}
++
++void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken)
++{
++    StackPrinter __stack_print__("ScExternalRefCache::setCellData");
++
++    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& rDoc = itrDoc->second;
++    
++    // See if the table by this name already exists.
++    TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(rTabName);
++    if (itrTabName == rDoc.maTableNameIndex.end())
++    {
++        // 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));
++
++        if (!res.second)
++            return;
++
++        itrTabName = res.first;
++    }
++
++    TableDataTypeRef pTableData = rDoc.maTables[itrTabName->second];
++    TableDataType::iterator itrRow = pTableData->find(nRow);
++    if (itrRow == pTableData->end())
++    {
++        // This row does not exist yet.
++        pair<TableDataType::iterator, bool> res = pTableData->insert(
++            TableDataType::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::setCellData:   token inserted\n");
++}
++
++void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange,
++                                          const vector<MatrixRef>& rData)
++{
++}
++
++// ============================================================================
++
 +ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
 +    ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
 +    mnFileId(nFileId),
@@ -2446,6 +4645,8 @@
 +
 +static ScToken* lcl_convertToToken(ScBaseCell* pCell)
 +{
++    StackPrinter __stack_print__("::lcl_convertToToken");
++
 +    if (!pCell)
 +        return NULL;
 +
@@ -2455,6 +4656,7 @@
 +        {
 +            String aStr;
 +            static_cast<ScStringCell*>(pCell)->GetString(aStr);
++            fprintf(stdout, "lcl_convertToToken:   string type (%s)\n", rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
 +            ScStringToken aToken(aStr);
 +            return aToken.Clone();
 +        }
@@ -2463,11 +4665,13 @@
 +        {
 +            double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
 +            ScDoubleToken aToken(fVal);
++            fprintf(stdout, "lcl_convertToToken:   value type (%g)\n", fVal);
 +            return aToken.Clone();
 +        }
 +        break;
 +        case CELLTYPE_FORMULA:
 +        {
++            fprintf(stdout, "lcl_convertToToken:   formula type\n");
 +            ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
 +            if (pFCell->IsValue())
 +            {
@@ -2582,6 +4786,64 @@
 +    clear();
 +}
 +
++ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
++                                                 const ScAddress* pCurPos, SCTAB* pTab)
++{
++    StackPrinter __stack_print__("ScExternalRefManager::getSingleRefToken");
++    fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   file id = %d; tab name = '%s'\n", nFileId, 
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
++
++    if (pTab)
++        *pTab = -1;
++
++    // Check if the given table name and the cell position is cached.
++    ScToken* pToken = maRefCache.getCellData(nFileId, rTabName, rCell.Row(), rCell.Col());
++    if (pToken)
++    {
++        fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   cell reference cached.\n");
++        return pToken;
++    }
++
++    fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   cell reference not cached.\n");
++
++    // reference not cached.  read from the source document.
++    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    if (!pSrcDoc)
++    {
++        fprintf(stdout, "ScExternalRefManager::getSingleRefToken:   source document NULL\n");
++        return NULL;
++    }
++
++    ScBaseCell* pCell = NULL;
++    SCTAB nTab;
++    if (!pSrcDoc->GetTable(rTabName, nTab))
++    {
++        // 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;
++    }
++
++    if (pTab)
++        *pTab = nTab;
++
++    pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
++    TokenRef pTok(lcl_convertToToken(pCell));
++
++    if (!pTok.get())
++    {
++        // Cell in the source document is probably empty.
++        pTok.reset(new ScEmptyCellToken(false, false));
++    }
++
++    // Now, insert the token into cache table.
++    maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok);
++    return pTok.get();
++}
++
++#if 1
 +ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress* pCurPos)
 +{
 +    if (pCurPos)
@@ -2628,14 +4890,35 @@
 +    fprintf(stdout, "ScExternalRefManager::getSingleRefToken: --end\n");
 +    return pTok.get();
 +}
++#endif
 +
-+ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress* pCurPos)
++ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
 +{
 +    if (pCurPos)
 +        insertReferencingCell(nFileId, *pCurPos);
-+    return getDoubleRefTokens(nFileId, rRange);
++
++    // 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())
++    {
++        fprintf(stdout, "ScExternalRefManager::getDoubleRefTokens:   range reference cached.\n");
++        return pArray.release();
++    }
++
++
++    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)
 +{
 +    {
@@ -2673,6 +4956,7 @@
 +    fprintf(stdout, "ScExternalRefManager::getDoubleRefToken: --end\n");
 +    return pArray.get();
 +}
++#endif
 +
 +ScTokenArray* ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
 +{
@@ -2732,7 +5016,7 @@
 +            case svSingleRef:
 +            {
 +                fprintf(stdout, "ScDocument::FindExternalRangeName:   single ref\n");
-+                ScExternalSingleRefToken aNewToken(nFileId, pToken->GetSingleRef());
++                ScExternalSingleRefToken aNewToken(nFileId, String(), pToken->GetSingleRef());
 +                pNew->AddToken(aNewToken);
 +                bTokenAdded = true;
 +            }
@@ -2740,7 +5024,7 @@
 +            case svDoubleRef:
 +            {
 +                fprintf(stdout, "ScDocument::FindExternalRangeName:   double ref\n");
-+                ScExternalDoubleRefToken aNewToken(nFileId, pToken->GetDoubleRef());
++                ScExternalDoubleRefToken aNewToken(nFileId, String(), pToken->GetDoubleRef());
 +                pNew->AddToken(aNewToken);
 +                bTokenAdded = true;
 +            }
@@ -2948,8 +5232,8 @@
 +    pCode->Reset();
 +    for (ScToken* p = pCode->First(); p; p = pCode->Next())
 +    {
-+        // TODO: once we have implemented a new token for the external
-+        // references, we will also query for that token type.
++        // External names, external cell and range references all have a 
++        // ocExternalName token.
 +        if (p->GetOpCode() == ocExternalName)
 +        {
 +            bCompile = true;
@@ -2972,7 +5256,7 @@
 +
 +void ScExternalRefManager::convertToAbsName(String& rFile) const
 +{
-+    ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell();
++    SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
 +    rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
 +}
 +
@@ -3012,6 +5296,31 @@
 +    return &pCache->maTableNames[nTabId];
 +}
 +
++SCTAB ScExternalRefManager::getExternalTableId(sal_uInt16 nFileId, const String& rTabName)
++{
++    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;
++}
++
 +template<typename MapContainer>
 +static void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
 +{
@@ -3139,3 +5448,47 @@
          $(SLO)$/tablink.obj   	\
          $(SLO)$/arealink.obj   	\
          $(SLO)$/dbdocfun.obj 	\
+diff --git sc/source/ui/view/viewfun3.cxx sc/source/ui/view/viewfun3.cxx
+index e42ed5d..e660e1c 100644
+--- sc/source/ui/view/viewfun3.cxx
++++ sc/source/ui/view/viewfun3.cxx
+@@ -212,6 +212,31 @@
+ 
+ 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;
++};
++
++}
++
+ // STATIC DATA ---------------------------------------------------------------
+ 
+ 
+@@ -748,6 +773,7 @@ BOOL ScViewFunc::PasteFromClip( USHORT nFlags, ScDocument* pClipDoc,
+ 									InsCellCmd eMoveMode, USHORT nUndoExtraFlags,
+ 									BOOL bAllowDialogs )
+ {
++    StackPrinter aStack("ScViewFunc::PasteFromClip");
+ 	if (!pClipDoc)
+ 	{
+ 		DBG_ERROR("PasteFromClip: pClipDoc=0 not allowed");



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