ooo-build r13761 - trunk/patches/test



Author: kyoshida
Date: Tue Sep  2 19:07:24 2008
New Revision: 13761
URL: http://svn.gnome.org/viewvc/ooo-build?rev=13761&view=rev

Log:
backup of patches before merging them into one.

Added:
   trunk/patches/test/calc-external-defined-names-offapi-before-merge.diff
   trunk/patches/test/calc-external-defined-names-sc-before-merge.diff
   trunk/patches/test/calc-external-names-additional-fixes-before-merge.diff

Added: trunk/patches/test/calc-external-defined-names-offapi-before-merge.diff
==============================================================================
--- (empty file)
+++ trunk/patches/test/calc-external-defined-names-offapi-before-merge.diff	Tue Sep  2 19:07:24 2008
@@ -0,0 +1,435 @@
+diff --git offapi/com/sun/star/sheet/ExternalDocLink.idl offapi/com/sun/star/sheet/ExternalDocLink.idl
+new file mode 100644
+index 0000000..7320905
+--- /dev/null
++++ offapi/com/sun/star/sheet/ExternalDocLink.idl
+@@ -0,0 +1,53 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_ExternalDocLink_idl__
++#define __com_sun_star_sheet_ExternalDocLink_idl__
++
++#include <com/sun/star/sheet/XExternalDocLink.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** Represents a single external document link. 
++
++    <p>An external document link contains cached data used for external cell
++    and cell range references as well as external range names.</p>
++
++    @see com::sun::star::sheet::XExternalDocLink
++
++    @since OOo 3.1.0
++ */
++service ExternalDocLink : XExternalDocLink
++{
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/ExternalDocLinks.idl offapi/com/sun/star/sheet/ExternalDocLinks.idl
+new file mode 100644
+index 0000000..105cb8f
+--- /dev/null
++++ offapi/com/sun/star/sheet/ExternalDocLinks.idl
+@@ -0,0 +1,55 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_ExternalDocLinks_idl__
++#define __com_sun_star_sheet_ExternalDocLinks_idl__
++
++#include <com/sun/star/sheet/XExternalDocLinks.idl>
++#include <com/sun/star/sheet/XSpreadsheetDocument.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** Represents a collection of external document links.
++
++    <p>An external document link contains cached data used for external cell
++    and cell range references as well as external range names.</p>
++
++    @see com::sun::star::sheet::ExternalDocLink
++    @see com::sun::star::sheet::XExternalDocLinks
++
++    @since OOo 3.1.0
++ */
++service ExternalDocLinks : XExternalDocLinks
++{
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/ExternalSheetCache.idl offapi/com/sun/star/sheet/ExternalSheetCache.idl
+new file mode 100644
+index 0000000..17af156
+--- /dev/null
++++ offapi/com/sun/star/sheet/ExternalSheetCache.idl
+@@ -0,0 +1,55 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_ExternalSheetCache_idl__
++#define __com_sun_star_sheet_ExternalSheetCache_idl__
++
++#include <com/sun/star/sheet/XExternalSheetCache.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** A single sheet cache for an external document.
++   
++    <p>This cached data is used for external cell and cell range references,
++    as well as external range names.  An <type scope="com::sun::star::sheet">ExternalDocLink</type>
++    instance contains a set of these sheet caches.</p>
++
++    @see com::sun::star::sheet::ExternalDocLink
++    @see com::sun::star::sheet::XExternalSheetCache
++    
++    @since OOo 3.1.0
++ */
++service ExternalSheetCache : XExternalSheetCache
++{
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/XExternalDocLink.idl offapi/com/sun/star/sheet/XExternalDocLink.idl
+new file mode 100644
+index 0000000..65928c5
+--- /dev/null
++++ offapi/com/sun/star/sheet/XExternalDocLink.idl
+@@ -0,0 +1,62 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_XExternalDocLink_idl__
++#define __com_sun_star_sheet_XExternalDocLink_idl__
++
++#include <com/sun/star/sheet/XExternalSheetCache.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** Primary interface for the <type scope="com::sun::star::sheet">ExternalDocLink</type> service.
++   
++    @see com::sun::star::sheet::ExternalDocLink
++
++    @since OOo 3.1.0
++ */
++interface XExternalDocLink
++{
++    /** <p>This method adds a new sheet cache instance to the extternal document 
++        link for a specified sheet name.  If a sheet cache instance already 
++        exists for the specified name, then the existing instance is returned.</p>
++
++        <p>Note that a sheet name lookup is performed in a case-insensitive 
++        fashion.</p>
++    
++        @param aSheetName sheet name
++
++        @return com::sun::star::sheet::XExternalSheetCache sheet cache instance
++     */
++    com::sun::star::sheet::XExternalSheetCache addSheetCache( [in] string aSheetName );
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/XExternalDocLinks.idl offapi/com/sun/star/sheet/XExternalDocLinks.idl
+new file mode 100644
+index 0000000..384d405
+--- /dev/null
++++ offapi/com/sun/star/sheet/XExternalDocLinks.idl
+@@ -0,0 +1,66 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_XExternalDocLinks_idl__
++#define __com_sun_star_sheet_XExternalDocLinks_idl__
++
++#include <com/sun/star/sheet/XExternalDocLink.idl>
++#include <com/sun/star/container/XNameAccess.idl>
++#include <com/sun/star/container/XIndexAccess.idl>
++#include <com/sun/star/container/XEnumerationAccess.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** Primary interface for the <type scope="com::sun::star::sheet">ExternalDocLinks</type> service.
++   
++    @see com::sun::star::sheet::ExternalDocLinks
++
++    @since OOo 3.1.0
++ */
++interface XExternalDocLinks
++{
++    interface com::sun::star::container::XNameAccess;
++    interface com::sun::star::container::XIndexAccess;
++    interface com::sun::star::container::XEnumerationAccess;
++
++    /** This method adds a new external document link by its URL, and returns 
++        its instance.  If an document instance already exists for the specified URL,
++        then that instance gets returned instead of creating a new one.
++    
++        @param aDocName document URL (e.g. file:///path/to/document.ods)
++       
++        @return com::sun::star::sheet::XExternalDocLink external document link instance
++     */
++    com::sun::star::sheet::XExternalDocLink addDocLink( [in] string aDocName );
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/XExternalSheetCache.idl offapi/com/sun/star/sheet/XExternalSheetCache.idl
+new file mode 100644
+index 0000000..0c35f7f
+--- /dev/null
++++ offapi/com/sun/star/sheet/XExternalSheetCache.idl
+@@ -0,0 +1,84 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: DDELink.idl,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef __com_sun_star_sheet_XExternalSheetCache_idl__
++#define __com_sun_star_sheet_XExternalSheetCache_idl__
++
++#include <com/sun/star/lang/IllegalArgumentException.idl>
++
++module com {  module sun {  module star {  module sheet {
++
++/** Primary interface for the <type scope="com::sun::star::sheet">ExternalSheetCache</type> service.
++   
++    @see com::sun::star::sheet::ExternalSheetCache
++
++    @since OOo 3.1.0
++ */
++interface XExternalSheetCache
++{
++    /** It sets a cached value for a specified cell position.  The value is expected
++        to be either of type <type>string</type> or of type <type>double</type>.  No
++        other data types are supported.
++
++        @param nRow row position (0-based)
++        @param nColumn column position (0-based)
++        @param aValue cell value to be cached
++     */
++    void setCellValue( [in] long nRow, [in] long nColumn, [in] any aValue )
++            raises (com::sun::star::lang::IllegalArgumentException);
++
++    /** It retrieves a cached value from a specified cell position.  The cached
++        value can be either <type>string</type> or <type>double</type>.
++    
++        @return any cached cell value
++     */
++    any getCellValue( [in] long nRow, [in] long nColumn )
++            raises (com::sun::star::lang::IllegalArgumentException);
++
++    /** It returns a list of all row numbers where a cached cell or cells exist.
++        The row numbers are sorted in ascending order.
++
++        @return sequence<long> list of all row numbers with cached cell(s)
++     */
++    sequence< long > getAllRows();
++
++    /** Given a row number, this method returns a list of all columns numbers 
++        that store cached cell values in that row.  The column numbers are 
++        sorted in ascending order.
++
++        @return sequence<long> list of all columns numbers with cached cell values
++     */
++    sequence< long > getAllColumns( [in] long nRow )
++            raises (com::sun::star::lang::IllegalArgumentException);
++};
++
++}; }; }; };
++
++#endif
+diff --git offapi/com/sun/star/sheet/makefile.mk offapi/com/sun/star/sheet/makefile.mk
+index c1d2844..16dffda 100644
+--- offapi/com/sun/star/sheet/makefile.mk
++++ offapi/com/sun/star/sheet/makefile.mk
+@@ -123,6 +123,9 @@ IDLFILES=\
+ 	DatabaseRangesEnumeration.idl\
+ 	DDELinkMode.idl\
+ 	DocumentSettings.idl\
++	ExternalDocLink.idl\
++	ExternalDocLinks.idl\
++	ExternalSheetCache.idl\
+ 	FillDateMode.idl\
+ 	FillDirection.idl\
+ 	FillMode.idl\
+@@ -255,6 +258,9 @@ IDLFILES=\
+ 	XDocumentAuditing.idl\
+ 	XDrillDownDataSupplier.idl\
+ 	XEnhancedMouseClickBroadcaster.idl\
++	XExternalDocLink.idl\
++	XExternalDocLinks.idl\
++	XExternalSheetCache.idl\
+ 	XExternalSheetName.idl\
+ 	XFillAcrossSheet.idl\
+ 	XFormulaOpCodeMapper.idl\

Added: trunk/patches/test/calc-external-defined-names-sc-before-merge.diff
==============================================================================
--- (empty file)
+++ trunk/patches/test/calc-external-defined-names-sc-before-merge.diff	Tue Sep  2 19:07:24 2008
@@ -0,0 +1,9415 @@
+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
++++ sc/inc/compiler.hrc
+@@ -39,25 +39,26 @@
+ #define SC_OPCODE_STOP                2
+ #define SC_OPCODE_EXTERNAL            3
+ #define SC_OPCODE_NAME                4
+-#define SC_OPCODE_IF                  5     /* jump commands */
+-#define SC_OPCODE_CHOSE               6
+-#define SC_OPCODE_OPEN                7     /* parentheses and separators */
+-#define SC_OPCODE_CLOSE               8
+-#define SC_OPCODE_SEP                 9
+-#define SC_OPCODE_MISSING            10     /* special OpCodes */
+-#define SC_OPCODE_BAD                11
+-#define SC_OPCODE_SPACES             12
+-#define SC_OPCODE_MAT_REF            13
+-#define SC_OPCODE_DB_AREA            14     /* additional access operators */
+-#define SC_OPCODE_MACRO              15
+-#define SC_OPCODE_COL_ROW_NAME       16
+-#define SC_OPCODE_COL_ROW_NAME_AUTO  17
+-#define SC_OPCODE_PERCENT_SIGN       18     /* operator _follows_ value */
+-#define SC_OPCODE_ARRAY_OPEN         19
+-#define SC_OPCODE_ARRAY_CLOSE        20
+-#define SC_OPCODE_ARRAY_ROW_SEP      21
+-#define SC_OPCODE_ARRAY_COL_SEP      22     /* some convs use sep != col_sep */
+-#define SC_OPCODE_STOP_DIV           23
++#define SC_OPCODE_EXTERNAL_NAME       5
++#define SC_OPCODE_IF                  6     /* jump commands */
++#define SC_OPCODE_CHOSE               7
++#define SC_OPCODE_OPEN                8     /* parentheses and separators */
++#define SC_OPCODE_CLOSE               9
++#define SC_OPCODE_SEP                10
++#define SC_OPCODE_MISSING            11     /* special OpCodes */
++#define SC_OPCODE_BAD                12
++#define SC_OPCODE_SPACES             13
++#define SC_OPCODE_MAT_REF            14
++#define SC_OPCODE_DB_AREA            15     /* additional access operators */
++#define SC_OPCODE_MACRO              16
++#define SC_OPCODE_COL_ROW_NAME       17
++#define SC_OPCODE_COL_ROW_NAME_AUTO  18
++#define SC_OPCODE_PERCENT_SIGN       19     /* operator _follows_ value */
++#define SC_OPCODE_ARRAY_OPEN         20
++#define SC_OPCODE_ARRAY_CLOSE        21
++#define SC_OPCODE_ARRAY_ROW_SEP      22
++#define SC_OPCODE_ARRAY_COL_SEP      23     /* some convs use sep != col_sep */
++#define SC_OPCODE_STOP_DIV           24
+ 
+ /*** error constants #... ***/
+ #define SC_OPCODE_START_ERRORS       30
+diff --git sc/inc/compiler.hxx sc/inc/compiler.hxx
+index 7bb6767..85fdf91 100644
+--- sc/inc/compiler.hxx
++++ sc/inc/compiler.hxx
+@@ -45,6 +45,7 @@
+ #include <unotools/charclass.hxx>
+ #include <rtl/ustrbuf.hxx>
+ #include <com/sun/star/uno/Sequence.hxx>
++#include <vector>
+ 
+ namespace com { namespace sun { namespace star {
+     namespace sheet {
+@@ -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 +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 +242,24 @@ public:
+                                    xub_StrLen nSrcPos,
+                                    const CharClass* pCharClass) const = 0;
+ 
++        /** 
++         * Parse the symbol string and pick up the file name and the external 
++         * range name. 
++         *
++         * @return true on successful parse, or false otherwise.
++         */
++        virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName ) const = 0;
++
++        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 = 0;
++
++        virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                         sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                         ScExternalRefManager* pRefMgr ) const = 0;
++
+         enum SpecialSymbolType
+         {
+             /** 
+@@ -448,6 +480,7 @@ private:
+     BOOL IsDoubleReference( const String& );
+     BOOL IsMacro( const String& );
+     BOOL IsNamedRange( const String& );
++    bool IsExternalNamedRange( const String& rSymbol );
+     BOOL IsDBRange( const String& );
+     BOOL IsColRowName( const String& );
+     BOOL IsBoolean( const String& );
+diff --git sc/inc/document.hxx sc/inc/document.hxx
+index a01f09b..5d4ca1f 100644
+--- sc/inc/document.hxx
++++ sc/inc/document.hxx
+@@ -93,6 +93,7 @@ class ScDocProtection;
+ class ScDocumentPool;
+ class ScDrawLayer;
+ class ScExtDocOptions;
++class ScExternalRefManager;
+ class ScFormulaCell;
+ class ScMarkData;
+ class ScOutlineTable;
+@@ -282,6 +283,7 @@ private:
+ 	ScFieldEditEngine*	pCacheFieldEditEngine;
+ 
+     ::std::auto_ptr<ScDocProtection> pDocProtection;
++    ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr;
+ 	String              aDocName;                       // opt: Dokumentname
+ 	String              aDocCodeName;                       // opt: Dokumentname
+ 	ScRangePairListRef	xColNameRanges;
+@@ -634,6 +636,8 @@ SC_DLLPUBLIC	ScDBCollection*	GetDBCollection() const;
+ 									const String& aFileName,
+ 									const String& aTabName );
+ 
++    ScExternalRefManager* GetExternalRefManager();
++
+     /** Creates a new sheet, and makes it linked to the specified sheet in an external document.
+         @param rnTab  (out-param) Returns the sheet index, if sheet could be inserted).
+         @return  TRUE = Sheet created, rnTab contains valid sheet index. */
+@@ -642,6 +646,7 @@ SC_DLLPUBLIC	ScDBCollection*	GetDBCollection() const;
+ 
+ 	BOOL			HasDdeLinks() const;
+ 	BOOL			HasAreaLinks() const;
++    void            UpdateExternalRefLinks();
+ 	void			UpdateDdeLinks();
+ 	void			UpdateAreaLinks();
+ 
+diff --git sc/inc/externalrefmgr.hxx sc/inc/externalrefmgr.hxx
+new file mode 100644
+index 0000000..46d691d
+--- /dev/null
++++ sc/inc/externalrefmgr.hxx
+@@ -0,0 +1,382 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: document.hxx,v $
++ * $Revision: 1.112 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_EXTERNALREFMGR_HXX
++#define SC_EXTERNALREFMGR_HXX
++
++#include "global.hxx"
++#include "address.hxx"
++#include "sfx2/objsh.hxx"
++#include "sfx2/lnkbase.hxx"
++#include "tools/time.hxx"
++#include "vcl/timer.hxx"
++#include "scmatrix.hxx"
++
++#include <hash_map>
++#include <hash_set>
++#include <boost/shared_ptr.hpp>
++#include <vector>
++
++class ScDocument;
++class ScToken;
++class ScMatrix;
++class ScTokenArray;
++class String;
++class SfxObjectShellRef;
++class Window;
++
++class ScExternalRefCache;
++
++class ScExternalRefLink : public ::sfx2::SvBaseLink
++{
++public:
++    ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter);
++    virtual ~ScExternalRefLink();
++
++    virtual void Closed();
++    virtual void DataChanged(const String& rMimeType, const ::com::sun::star::uno::Any & rValue);
++    virtual void Edit(Window* pParent, const Link& rEndEditHdl);
++
++    void SetDoReferesh(bool b);
++
++private:
++    ScExternalRefLink(); // disabled
++    ScExternalRefLink(const ScExternalRefLink&); // disabled
++
++    DECL_LINK(EndEditHdl, void*);
++
++    sal_uInt16  mnFileId;
++    String      maFilterName;
++    ScDocument* mpDoc;
++    bool        mbDoRefresh;
++};
++
++// ============================================================================
++
++/** 
++ * Cache table for external reference data.
++ */
++class ScExternalRefCache
++{
++    struct RangeHash
++    {
++        size_t operator()(const ScRange& rRange) const
++        {
++            const ScAddress& s = rRange.aStart;
++            const ScAddress& e = rRange.aEnd;
++            return s.Tab() + s.Col() + s.Row() + e.Tab() + e.Col() + e.Row();
++        }
++    };
++
++public:
++    
++    typedef ::boost::shared_ptr<ScToken>            TokenRef;
++    typedef ::boost::shared_ptr<ScTokenArray>       TokenArrayRef;
++    typedef ::std::hash_map<SCCOL, TokenRef>        RowDataType;
++    typedef ::std::hash_map<SCROW, RowDataType>     RowsDataType;
++
++    class Table
++    {
++    public:
++        Table();
++        ~Table();
++
++        void setCell(SCROW nRow, SCCOL nCol, TokenRef pToken);
++        TokenRef getCell(SCROW nRow, SCCOL nCol) const;
++        void getAllRows(::std::vector<SCROW>& rRows) const;
++        void getAllCols(SCROW nRow, ::std::vector<SCCOL>& rCols) const;
++
++    private:
++        RowsDataType maRows;
++    };
++
++    typedef ::boost::shared_ptr<Table>      TableTypeRef;
++    typedef ::std::hash_map<String, size_t, ScStringHashCode>   TableNameIndexMap;
++
++    ScExternalRefCache();
++    ~ScExternalRefCache();
++
++    /** 
++     * Get a cached cell data at specified cell location.
++     *
++     * @param nFileId file ID of an external document
++     * @param rTabName sheet name
++     * @param nRow 
++     * @param nCol 
++     * 
++     * @return pointer to the token instance in the cache.  <i>The caller does
++     *         not need to delete this instance since its life cycle is
++     *         managed by this class.</i>
++     */
++    ScToken* getCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol);
++
++    /** 
++     * Get a cached cell range data. 
++     *  
++     * @return a new token array instance.  Note that <i>the caller must 
++     *         manage the life cycle of the returned instance</i>.
++     */
++    ScTokenArray* getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange);
++
++    ScTokenArray* getRangeNameTokens(sal_uInt16 nFileId, const String& rName);
++    void setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray);
++
++    void setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken);
++
++    struct SingleRangeData
++    {
++        String      maTableName;
++        ScMatrixRef mpRangeData;
++    };
++    void setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const ::std::vector<SingleRangeData>& rData,
++                          TokenArrayRef pArray);
++
++    bool isDocInitialized(sal_uInt16 nFileId);
++    void initializeDoc(sal_uInt16 nFileId, const ::std::vector<String>& rTabNames);
++    const ::std::vector<String>* getAllTableNames(sal_uInt16 nFileId) const;
++
++    /** 
++     * Get a cache table instance for specified file and table name.  If the 
++     * table instance is not already present, it'll instantiate a new one and 
++     * append it to the end of the table array.  <I>It's important to be 
++     * aware of this fact especially for multi-table ranges for which 
++     * table orders are critical.</I> 
++     *  
++     * Excel filter calls this method to populate the cache table from the 
++     * XCT/CRN records. 
++     *
++     * @param nFileId file ID
++     * @param rTabName table name
++     * 
++     * @return pointer to the cache table instance
++     */
++    Table* getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew);
++
++    void clearCache(sal_uInt16 nFileId);
++
++private:
++    typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode>    RangeNameMap;
++    typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash>          RangeArrayMap;
++
++    /** Represents data cached for a single external document. */
++    struct DocItem
++    {
++        ::std::vector<TableTypeRef> maTables;
++        ::std::vector<String>       maTableNames; 
++        TableNameIndexMap           maTableNameIndex;
++        RangeNameMap                maRangeNames;
++        RangeArrayMap               maRangeArrays;
++
++        bool mbInitFromSource;
++
++        DocItem() : mbInitFromSource(false) {}
++    };
++    typedef ::std::hash_map<sal_uInt16, DocItem>  DocDataType;
++    DocItem* getDocItem(sal_uInt16 nFileId) const;
++
++private:
++    mutable DocDataType maDocs;
++};
++
++// ============================================================================
++
++class ScExternalRefManager
++{
++private:
++    struct AddressHash
++    {
++        size_t operator()(const ScAddress& rAddr) const
++        {
++            // dumb hashing - how do we properly hash a cell address?
++            return rAddr.Tab() + rAddr.Col() + rAddr.Row();
++        }
++    };
++
++    /** Shell instance for a source document. */
++    struct SrcShell
++    {
++        SfxObjectShellRef   maShell;
++        Time                maLastAccess;
++    };
++
++    typedef ::boost::shared_ptr<ScToken>        TokenRef;
++    typedef ::boost::shared_ptr<ScTokenArray>   TokenArrayRef;
++
++    typedef ::std::hash_map<sal_uInt16, SrcShell>                                   DocShellMap;
++    typedef ::std::hash_set<sal_uInt16>                                             LinkedDocSet;
++
++    typedef ::std::hash_set<ScAddress, AddressHash, ::std::equal_to<ScAddress> >    RefCellSet;
++    typedef ::std::hash_map<sal_uInt16, RefCellSet>                                 RefCellMap;
++
++public:
++    /** Source document meta-data container. */
++    struct SrcFileData
++    {
++        String maFileName;
++        String maRelativeName;
++        String maFilterName;
++        String maFilterOptions;
++    };
++
++public:
++    explicit ScExternalRefManager(ScDocument* pDoc);
++    ~ScExternalRefManager();
++
++    ScExternalRefCache::Table* getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew = true);
++    void storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray);
++
++    ScToken* getSingleRefToken(sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell, const ScAddress* pCurPos, SCTAB* pTab);
++
++    /** 
++     * Get an array of tokens that consist of the specified external cell 
++     * range. 
++     *
++     * @param nFileId file ID for an external document
++     * @param rTabName referenced sheet name
++     * @param rRange referenced cell range
++     * @param pCurPos current cursor position to keep track of cells that 
++     *                reference an external data.
++     * 
++     * @return pointer to a token array instance.  <i>The caller must not 
++     *         delete the instance returned by this method.</i>
++     */
++    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos);
++
++    /** 
++     * Get an array of tokens corresponding with a specified name in a 
++     * specified file. 
++     *  
++     * @param pCurPos currnet cell address where this name token is used. 
++     *                This is purely to keep track of all cells containing
++     *                external names for refreshing purposes.  If this is
++     *                NULL, then the cell will not be added to the list.
++     * 
++     * @return array of tokens composing the name
++     */
++    ScTokenArray* getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos = NULL);
++
++    const String& getOwnDocumentName() const;
++    bool isOwnDocument(const String& rFile) const;
++
++    /** 
++     * Takes a flat file name, and convert it to an absolute URL path.  An 
++     * absolute URL path begines with 'file:///. 
++     *
++     * @param rFile file name to convert 
++     */
++    void convertToAbsName(String& rFile) const;
++    sal_uInt16 getExternalFileId(const String& rFile);
++    const String* getExternalFileName(sal_uInt16 nFileId) const;
++    const SrcFileData* getExternalFileData(sal_uInt16 nFileId) const;
++
++    const ::std::vector<String>* getAllCachedTableNames(sal_uInt16 nFileId) const;
++    sal_uInt16 getCachedFileCount() const;
++    void refreshNames(sal_uInt16 nFileId);
++    void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile);
++
++    void setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl);
++
++    /** 
++     * Set the filter name and options if any for a given source document. 
++     * These values get reset whne the source document ever gets reloaded. 
++     *
++     * @param nFileId 
++     * @param rFilterName 
++     * @param rOptions 
++     * @return 
++     */
++    void setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions);
++
++    void removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink);
++    void clear();
++
++    bool hasExternalData() const;
++
++    /** 
++     * Re-generates relative names for all stored source files.  This is 
++     * necessary when exporting to an ods document, to ensure that all source 
++     * files have their respective relative names for xlink:href export.
++     */
++    void resetSrcFileData();
++
++private:
++    ScExternalRefManager();
++    ScExternalRefManager(const ScExternalRefManager&); 
++
++    void refreshAllReferencingCells(sal_uInt16 nFileId);
++
++    void insertReferencingCell(sal_uInt16 nFileId, const ScAddress& rCell);
++
++    ScDocument* getSrcDocument(sal_uInt16 nFileId);
++    SfxObjectShellRef loadSrcDocument(sal_uInt16 nFileId, String& rFilter);
++    bool isFileLoadable(const String& rFile) const;
++
++    void maybeLinkExternalFile(sal_uInt16 nFileId);
++
++    bool compileTokensByCell(const ScAddress& rCell);
++
++    /** 
++     * Purge those source document instances that have not been accessed for 
++     * the specified duration.
++     *  
++     * @param nTimeOut time out value in 100th of a second 
++     */
++    void purgeStaleSrcDocument(sal_Int32 nTimeOut);
++
++private:
++    /** cache of referenced ranges and names from source documents. */
++    ScExternalRefCache maRefCache;
++
++    ScDocument* mpDoc;
++
++    /** 
++     * Source document cache.  This stores the original source document shell 
++     * instances.  They get purged after a certain period of time.
++     */
++    DocShellMap maDocShells;
++
++    /** list of source documents that are managed by the link manager. */
++    LinkedDocSet maLinkedDocs;
++
++    /** 
++     * List of referencing cells that may contain external names.  There is
++     * one list per source document.
++     */
++    RefCellMap maRefCells;
++
++    /** original source file index. */
++    ::std::vector<SrcFileData> maSrcFiles;
++
++    AutoTimer maSrcDocTimer;
++    DECL_LINK(TimeOutHdl, AutoTimer*);
++};
++
++
++#endif
+diff --git sc/inc/linkuno.hxx sc/inc/linkuno.hxx
+index b6fc524..926fed7 100644
+--- sc/inc/linkuno.hxx
++++ sc/inc/linkuno.hxx
+@@ -36,6 +36,9 @@
+ #include <com/sun/star/sheet/XDDELink.hpp>
+ #include <com/sun/star/sheet/XDDELinkResults.hpp>
+ #include <com/sun/star/sheet/XDDELinks.hpp>
++#include <com/sun/star/sheet/XExternalDocLink.hpp>
++#include <com/sun/star/sheet/XExternalDocLinks.hpp>
++#include <com/sun/star/sheet/XExternalSheetCache.hpp>
+ #include <com/sun/star/sheet/XAreaLink.hpp>
+ #include <com/sun/star/sheet/XAreaLinks.hpp>
+ #include <com/sun/star/util/XRefreshable.hpp>
+@@ -45,10 +48,15 @@
+ #include <com/sun/star/container/XNameAccess.hpp>
+ #include <com/sun/star/container/XIndexAccess.hpp>
+ #include <com/sun/star/container/XNamed.hpp>
++#include <cppuhelper/implbase1.hxx>
+ #include <cppuhelper/implbase3.hxx>
+ #include <cppuhelper/implbase4.hxx>
+ #include <cppuhelper/implbase5.hxx>
+ 
++#include "externalrefmgr.hxx"
++
++#include <hash_map>
++#include <vector>
+ 
+ class ScAreaLink;
+ class ScDocShell;
+@@ -493,8 +501,108 @@ public:
+ 								throw(::com::sun::star::uno::RuntimeException);
+ };
+ 
++// ============================================================================
++
++class ScExternalSheetCacheObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalSheetCache >
++{
++public:
++    explicit ScExternalSheetCacheObj(ScExternalRefCache::Table* pTable);
++    ~ScExternalSheetCacheObj();
++
++                            // XExternalSheetCache
++    virtual void SAL_CALL setCellValue(
++        sal_Int32 nRow, sal_Int32 nCol, const ::com::sun::star::uno::Any& rAny)
++        throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
++
++    virtual ::com::sun::star::uno::Any SAL_CALL getCellValue(sal_Int32 nRow, sal_Int32 nCol)
++        throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
++
++    virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL getAllRows()
++        throw (::com::sun::star::uno::RuntimeException);
++
++    virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL getAllColumns(sal_Int32 nRow)
++        throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
++
++private:
++    ScExternalSheetCacheObj();
++    ScExternalSheetCacheObj(const ScExternalSheetCacheObj&);
++
++private:
++    ScExternalRefCache::Table* mpTable;
++};
++
++// ============================================================================
++
++class ScExternalDocLinkObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalDocLink >
++{
++public:
++    ScExternalDocLinkObj(ScExternalRefManager* pRefMgr, sal_uInt16 nFileId);
++    ~ScExternalDocLinkObj();
++
++                            // XExternalDocLink
++    virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalSheetCache > 
++        SAL_CALL addSheetCache( const ::rtl::OUString& aSheetName ) 
++            throw (::com::sun::star::uno::RuntimeException);
++
++private:
++    ScExternalRefManager*   mpRefMgr;
++    sal_uInt16              mnFileId;
++};
++
++// ============================================================================
+ 
++/** This is the UNO API equivalent of ScExternalRefManager. */
++class ScExternalDocLinksObj : public cppu::WeakImplHelper1< ::com::sun::star::sheet::XExternalDocLinks >
++{
++public:
++    ScExternalDocLinksObj(ScDocShell* pDocShell);
++    ~ScExternalDocLinksObj();
+ 
++                            // XExternalDocLinks
++    virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalDocLink > 
++        SAL_CALL addDocLink( const ::rtl::OUString& aDocName ) 
++            throw (::com::sun::star::uno::RuntimeException);
++
++							// XNameAccess
++	virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName )
++								throw(::com::sun::star::container::NoSuchElementException,
++									::com::sun::star::lang::WrappedTargetException,
++									::com::sun::star::uno::RuntimeException);
++	virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames()
++								throw(::com::sun::star::uno::RuntimeException);
++	virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName )
++								throw(::com::sun::star::uno::RuntimeException);
++
++							// XIndexAccess
++	virtual sal_Int32 SAL_CALL getCount() throw(::com::sun::star::uno::RuntimeException);
++	virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 nIndex )
++								throw(::com::sun::star::lang::IndexOutOfBoundsException,
++									::com::sun::star::lang::WrappedTargetException,
++									::com::sun::star::uno::RuntimeException);
++
++							// XEnumerationAccess
++	virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XEnumeration > SAL_CALL
++							createEnumeration() throw(::com::sun::star::uno::RuntimeException);
++
++							// XElementAccess
++	virtual ::com::sun::star::uno::Type SAL_CALL getElementType()
++								throw(::com::sun::star::uno::RuntimeException);
++	virtual sal_Bool SAL_CALL hasElements() throw(::com::sun::star::uno::RuntimeException);
++
++private:
++    ScExternalDocLinksObj();
++    ScExternalDocLinksObj(const ScExternalDocLinksObj&);
++
++private:
++    typedef ::std::hash_map< 
++        ::rtl::OUString, 
++        ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XExternalDocLink >, 
++        ::rtl::OUStringHash > DocLinkMap;
++    DocLinkMap                          maDocLinks;
++    ::std::vector< ::rtl::OUString >    maDocNames;
++    ScDocShell*                         mpDocShell;
++    ScExternalRefManager*               mpRefMgr;
++};
+ 
+ #endif
+ 
+diff --git sc/inc/opcode.hxx sc/inc/opcode.hxx
+index 285104d..b72ebad 100644
+--- sc/inc/opcode.hxx
++++ sc/inc/opcode.hxx
+@@ -44,6 +44,7 @@ enum OpCodeEnum
+ 		ocStop				= SC_OPCODE_STOP,
+ 		ocExternal			= SC_OPCODE_EXTERNAL,
+ 		ocName				= SC_OPCODE_NAME,
++        ocExternalName      = SC_OPCODE_EXTERNAL_NAME,
+ 	// Jump commands
+ 		ocIf				= SC_OPCODE_IF,
+ 		ocChose				= SC_OPCODE_CHOSE,
+diff --git sc/inc/refdata.hxx sc/inc/refdata.hxx
+index 92d1320..9e83a45 100644
+--- sc/inc/refdata.hxx
++++ sc/inc/refdata.hxx
+@@ -116,6 +116,7 @@ struct SingleRefData        // Single reference (one address) into the sheet
+             BYTE CreateStoreByteFromFlags() const;
+             void CreateFlagsFromLoadByte( BYTE );
+             BOOL operator==( const SingleRefData& ) const;
++            bool operator!=( const SingleRefData& ) const;
+ };
+ 
+ inline void SingleRefData::InitAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP )
+diff --git sc/inc/token.hxx sc/inc/token.hxx
+index ded3a94..7e49031 100644
+--- sc/inc/token.hxx
++++ sc/inc/token.hxx
+@@ -64,7 +64,7 @@ enum StackVarEnum
+                                         // cell during import, having a double
+                                         // and/or string result and a formula
+                                         // string to be compiled.
+-
++    svExternalName,
+     svError,                            // error token
+     svMissing = 0x70,                   // 0 or ""
+     svSep,                              // separator, ocSep, ocOpen, ocClose
+@@ -448,6 +448,69 @@ public:
+ };
+ 
+ 
++class ScExternalSingleRefToken : public ScOpToken
++{
++private:
++    sal_uInt16                  mnFileId;
++    String                      maTabName;
++    SingleRefData               maSingleRef;
++
++                                ScExternalSingleRefToken(); // disabled
++public:
++                                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;
++};
++
++
++class ScExternalDoubleRefToken : public ScOpToken
++{
++private:
++    sal_uInt16                  mnFileId;
++    String                      maTabName;  // name of the first sheet
++    ComplRefData                maDoubleRef;
++
++                                ScExternalDoubleRefToken(); // disabled
++public:
++                                ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r );
++                                ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r );
++    virtual                     ~ScExternalDoubleRefToken();
++
++    virtual USHORT                 GetIndex() const;
++    virtual const String&          GetString() const;
++    virtual const SingleRefData&   GetSingleRef() const;
++    virtual SingleRefData&         GetSingleRef();
++    virtual const SingleRefData&   GetSingleRef2() const;
++    virtual SingleRefData&         GetSingleRef2();
++    virtual const ComplRefData&    GetDoubleRef() const;
++    virtual ComplRefData&          GetDoubleRef();
++    virtual BOOL                    operator==( const ScToken& rToken ) const;
++};
++
++
++class ScExternalNameToken : public ScOpToken
++{
++private:
++    sal_uInt16                  mnFileId;
++    String                      maName;
++private:
++                                ScExternalNameToken(); // disabled
++public:
++                                ScExternalNameToken( sal_uInt16 nFileId, const String& rName );
++                                ScExternalNameToken( const ScExternalNameToken& r );
++    virtual                     ~ScExternalNameToken();
++    virtual USHORT              GetIndex() const;
++    virtual const String&       GetString() const;
++    virtual BOOL                operator==( const ScToken& rToken ) const;
++};
++
++
+ class ScJumpToken : public ScOpToken
+ {
+ private:
+diff --git sc/inc/tokenarray.hxx sc/inc/tokenarray.hxx
+index 1d903ce..1e94c2f 100644
+--- sc/inc/tokenarray.hxx
++++ sc/inc/tokenarray.hxx
+@@ -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/inc/unonames.hxx sc/inc/unonames.hxx
+index b2c45ac..51ebf60 100644
+--- sc/inc/unonames.hxx
++++ sc/inc/unonames.hxx
+@@ -47,6 +47,7 @@
+ //	document
+ #define SC_UNO_AREALINKS			"AreaLinks"
+ #define SC_UNO_DDELINKS				"DDELinks"
++#define SC_UNO_EXTERNALDOCLINKS     "ExternalDocLinks"
+ #define SC_UNO_COLLABELRNG			"ColumnLabelRanges"
+ #define SC_UNO_DATABASERNG			"DatabaseRanges"
+ #define SC_UNO_NAMEDRANGES			"NamedRanges"
+diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
+index 1c7ac08..4611515 100644
+--- sc/source/core/data/cell.cxx
++++ sc/source/core/data/cell.cxx
+@@ -689,7 +689,12 @@ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rNewPos,
+ 		for( ScToken* t = pCode->GetNextReferenceOrName(); t && !bCompile;
+ 					  t = pCode->GetNextReferenceOrName() )
+ 		{
+-			if ( t->GetType() == svIndex )
++            if ( t->GetOpCode() == ocExternalName )
++            {
++                // External name, cell, and area references.
++                bCompile = true;
++            }
++			else if ( t->GetType() == svIndex )
+ 			{
+ 				ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() );
+ 				if( pRangeData )
+diff --git sc/source/core/data/documen2.cxx sc/source/core/data/documen2.cxx
+index b75279e..d739a17 100644
+--- sc/source/core/data/documen2.cxx
++++ sc/source/core/data/documen2.cxx
+@@ -94,6 +94,7 @@
+ #include "recursionhelper.hxx"
+ #include "lookupcache.hxx"
+ #include "tabprotection.hxx"
++#include "externalrefmgr.hxx"
+ #include <com/sun/star/document/XVbaEventsHelper.hpp>
+ 
+ // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and
+@@ -153,6 +154,7 @@ ScDocument::ScDocument( ScDocumentMode	eMode,
+ 		pScriptTypeData( NULL ),
+         pCacheFieldEditEngine( NULL ),
+         pDocProtection( NULL ),
++        pExternalRefMgr( NULL ),
+ 		pViewOptions( NULL ),
+ 		pDocOptions( NULL ),
+ 		pExtDocOptions( NULL ),
+@@ -383,6 +385,11 @@ ScDocument::~ScDocument()
+ 			pLinkManager->Remove( 0, pLinkManager->GetLinks().Count() );
+ 	}
+ 
++    if (pExternalRefMgr.get())
++        // Destroy the external ref mgr instance here because it has a timer 
++        // which needs to be stopped before the app closes.
++        pExternalRefMgr.reset(NULL);
++
+ 	ScAddInAsync::RemoveDocument( this );
+ 	ScAddInListener::RemoveDocument( this );
+ 	delete pChartListenerCollection;	// vor pBASM wg. evtl. Listener!
+diff --git sc/source/core/data/documen3.cxx sc/source/core/data/documen3.cxx
+index 541e2e4..20dae1e 100644
+--- sc/source/core/data/documen3.cxx
++++ sc/source/core/data/documen3.cxx
+@@ -61,6 +61,7 @@
+ #include "brdcst.hxx"
+ #include "bcaslot.hxx"
+ #include "tablink.hxx"
++#include "externalrefmgr.hxx"
+ #include "markdata.hxx"
+ #include "validat.hxx"
+ #include "dociter.hxx"
+@@ -81,7 +82,10 @@
+ #include "svtools/PasswordHelper.hxx"
+ #include "tabprotection.hxx"
+ 
++#include <memory>
++
+ using namespace com::sun::star;
++using ::std::auto_ptr;
+ 
+ //------------------------------------------------------------------------
+ 
+@@ -478,6 +482,14 @@ BOOL ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab,
+ 	return TRUE;
+ }
+ 
++ScExternalRefManager* ScDocument::GetExternalRefManager()
++{
++    if (!pExternalRefMgr.get())
++        pExternalRefMgr.reset(new ScExternalRefManager(this));
++
++    return pExternalRefMgr.get();
++}
++
+ BOOL ScDocument::InsertLinkedEmptyTab( SCTAB& rnTab, const String& rFileName,
+         const String& rFilterName, const String& rFilterOpt, const String& rTabName )
+ {
+diff --git sc/source/core/data/documen8.cxx sc/source/core/data/documen8.cxx
+index fd09e93..719206e 100644
+--- sc/source/core/data/documen8.cxx
++++ sc/source/core/data/documen8.cxx
+@@ -91,6 +91,7 @@
+ #include "markdata.hxx"
+ #include "scmod.hxx"
+ #include "printopt.hxx"
++#include "externalrefmgr.hxx"
+ #include "globstr.hrc"
+ #include "sc.hrc"
+ 
+@@ -1062,6 +1063,33 @@ BOOL ScDocument::IsInLinkUpdate() const
+     return bInLinkUpdate || IsInDdeLinkUpdate();
+ }
+ 
++void ScDocument::UpdateExternalRefLinks()
++{
++    if (!pLinkManager)
++        return;
++
++    const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
++    USHORT nCount = rLinks.Count();
++
++    bool bAny = false;
++    for (USHORT i = 0; i < nCount; ++i)
++    {
++        ::sfx2::SvBaseLink* pBase = *rLinks[i];
++        ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase);
++        if (pRefLink)
++        {
++            pRefLink->Update();
++            bAny = true;
++        }
++    }
++    if (bAny)
++    {
++        TrackFormulas();
++        pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) );
++        ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) );
++    }
++}
++
+ void ScDocument::UpdateDdeLinks()
+ {
+     if (pLinkManager)
+diff --git sc/source/core/tool/address.cxx sc/source/core/tool/address.cxx
+index 2cb5dce..e518b27 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>
+@@ -68,6 +69,49 @@ void ScAddress::Details::SetPos ( const ScDocument* pDoc,
+ 
+ #include <iostream>
+ 
++/** 
++ * Parse from the opening single quote to the closing single quote.  Inside 
++ * the quotes, a single quote character is encoded by double single-quote 
++ * characters. 
++ *
++ * @param p pointer to the first character to begin parsing. 
++ * @param rName (reference) parsed name within the quotes.  If the name is 
++ *              empty, either the parsing failed or it's an empty quote.
++ * 
++ * @return pointer to the character immediately after the closing single 
++ *         quote.
++ */
++static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName )
++{
++    rName.Erase();
++    if (*p != '\'')
++        return p;
++
++    const sal_Unicode* pStart = p;
++    sal_Unicode cPrev = 0;
++    for (++p; *p; ++p)
++    {
++        if (*p == '\'')
++        {
++            if (cPrev == '\'')
++            {    
++                // double single-quote equals one single quote.
++                rName += *p;
++                cPrev = 0;
++                continue;
++            }
++        }
++        else if (cPrev == '\'')
++            // We are past the closing quote.  We're done!
++            return p;
++        else
++            rName += *p;
++        cPrev = *p;
++    }
++    rName.Erase();
++    return pStart;
++}
++
+ static long int
+ sal_Unicode_strtol ( const sal_Unicode*  p,
+                      const sal_Unicode** pEnd )
+@@ -102,31 +146,18 @@ sal_Unicode_strtol ( const sal_Unicode*  p,
+ // Returns NULL if the string should be a sheet name, but is invalid
+ // Returns a pointer to the first character after the sheet name
+ static const sal_Unicode *
+-lcl_XL_ParseSheetRef( const sal_Unicode *start,
+-                      ScAddress *pAddr,
+-                      const ScDocument* pDoc,
+-                      const String& rDocName,
++lcl_XL_ParseSheetRef( const sal_Unicode* start,
+                       String& rExternTabName,
+                       bool allow_3d )
+ {
+     String aTabName;
+-    SCTAB  nTab = 0;
+     const sal_Unicode *p = start;
+ 
+     //pAddr->SetTab( 0 );
+     if( *p == '\'' ) // XL only seems to use single quotes for sheet names
+     {
+-        for( p++; *p ; )
+-        {
+-            if( *p == '\'' )
+-            {
+-                if( p[1] != '\'' )  // end quote
+-                    break;
+-                p++;    // 2 quotes in a row are a quote in a the name
+-            }
+-            aTabName += *p++;
+-        }
+-        if( *p++ != '\'' )
++        p = lcl_ParseQuotedName(p, aTabName);
++        if (!aTabName.Len())
+             return NULL;
+     }
+     else
+@@ -190,26 +221,7 @@ lcl_XL_ParseSheetRef( const sal_Unicode *start,
+         aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) );
+     }
+ 
+-    if( pDoc )
+-    {
+-        if( rDocName.Len() > 0 )
+-        {
+-            // This is a simplification of the OOo code which does an
+-            // optimization to manually construct the DocTab before calling
+-            // GetDocTabName
+-            String aDocTab = ScGlobal::GetDocTabName( rDocName, aTabName );
+-            if( !pDoc->GetTable( aDocTab, nTab ) &&
+-                 pDoc->ValidTabName( aTabName ) &&
+-                !pDoc->GetTable( aDocTab, nTab ) )
+-            {
+-                rExternTabName = aDocTab;
+-            }
+-        }
+-        else if( !pDoc->GetTable( aTabName, nTab ) )
+-            return start;
+-    }
+-
+-    pAddr->SetTab( nTab );
++    rExternTabName = aTabName;
+     return p;
+ }
+ 
+@@ -227,39 +239,33 @@ lcl_ScRange_Parse_XL_Header( ScRange& r,
+     // Is this an external reference ?
+     rStartTabName.Erase();
+     rEndTabName.Erase();
+-    if( *p == '[' )
++    rExternDocName.Erase();
++    if (*p == '[')
+     {
+-        p++;
+-        // TODO : Get more detail on how paths are quoted
+-        // 1) I suspect only single quote is correct
+-        // 2) check whether this is another doubled quote rather than a
+-        //    backslash
+-        if( *p == '\'' || *p == '\"' )
++        ++p;
++        // Only single quotes are correct, and a double single quote escapes a
++        // single quote text inside the quoted text.
++        if (*p == '\'')
+         {
+-            for( const sal_Unicode cQuote = *p++; *p && *p != cQuote ; )
+-            {
+-                if( *p == '\\' && p[1] )
+-                    p++;
+-                rExternDocName += *p++;
+-            }
++            p = lcl_ParseQuotedName(p, rExternDocName);
++            if (!*p || *p != ']' || !rExternDocName.Len())
++                return start;
+         }
+         else
+         {
++            // non-quoted file name.
+             p = ScGlobal::UnicodeStrChr( start+1, ']' );
+             if( p == NULL )
+                 return start;
+             rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) );
+         }
+ 
+-        rExternDocName = ScGlobal::GetAbsDocName( rExternDocName,
+-            pDoc->GetDocumentShell() );
+-        if( *p != ']' )
+-            return start;
+-        p++;
++        rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell());
++        ++p;
+     }
+ 
+     startTabs = p;
+-    p = lcl_XL_ParseSheetRef( p, &r.aStart, pDoc, rExternDocName, rStartTabName, TRUE );
++    p = lcl_XL_ParseSheetRef( p, rStartTabName, TRUE );
+     if( NULL == p )
+         return start;       // invalid tab
+     if( p != startTabs )
+@@ -267,7 +273,7 @@ lcl_ScRange_Parse_XL_Header( ScRange& r,
+         nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE;
+         if( *p == ':' ) // 3d ref
+         {
+-            p = lcl_XL_ParseSheetRef( p+1, &r.aEnd, pDoc, rExternDocName, rEndTabName, FALSE );
++            p = lcl_XL_ParseSheetRef( p+1, rEndTabName, FALSE );
+             if( p == NULL )
+                 return start; // invalid tab
+             nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE;
+@@ -289,45 +295,36 @@ lcl_ScRange_Parse_XL_Header( ScRange& r,
+         // Use the current tab, it needs to be passed in. : r.aEnd.SetTab( .. );
+     }
+ 
+-    return p;
+-}
+-
+-static USHORT
+-lcl_XL_LinkSheetRef( ScRange& r,
+-                     ScDocument* pDoc,
+-                     const String& rExternDocName,
+-                     const String& rStartTabName,
+-                     const String& rEndTabName,
+-                     USHORT nFlags )
+-{
+-    SCTAB nTab;
+-
+-    if( rExternDocName.Len() > 0 )
++    if (!rExternDocName.Len())
+     {
+-        String aDocName = ScGlobal::GetAbsDocName( rExternDocName,
+-                                                   pDoc->GetDocumentShell() );
++        // Internal reference.
++        if (!rStartTabName.Len())
++            return start;
+ 
+-        String aDocTab;
+-       
+-        aDocTab = ScGlobal::GetDocTabName( aDocName, rStartTabName );
+-        if( !pDoc->LinkExternalTab( nTab, aDocTab, rExternDocName, rStartTabName ) )
+-            return 0;
+-        r.aStart.SetTab( nTab );
++        SCTAB nTab;
++        if (!pDoc->GetTable(rStartTabName, nTab))
++        {
++            // invalid table name.
++            nFlags &= ~SCA_VALID_TAB;
++            nTab = -1;
++        }
++
++        r.aStart.SetTab(nTab);
++        r.aEnd.SetTab(nTab);
+ 
+-        if( rEndTabName.Len() > 0 &&
+-            rStartTabName != rEndTabName )
++        if (rEndTabName.Len())
+         {
+-            aDocTab = ScGlobal::GetDocTabName( aDocName, rEndTabName );
+-            if( !pDoc->LinkExternalTab( nTab, aDocTab, rExternDocName, rEndTabName ) )
+-            {
+-                DBG_ASSERT( r.IsValid(), "lcl_XL_LinkSheetRef - unable to link endTab of 3d ref" );
+-                return 0;
++            if (!pDoc->GetTable(rEndTabName, nTab))
++            {    
++                // invalid table name.
++                nFlags &= ~SCA_VALID_TAB2;
++                nTab = -1;
+             }
++                
++            r.aEnd.SetTab(nTab);
+         }
+-        r.aEnd.SetTab( nTab );
+     }
+-
+-    return nFlags;
++    return p;
+ }
+ 
+ 
+@@ -427,7 +424,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+                            const sal_Unicode* p,
+                            ScDocument* pDoc,
+                            const ScAddress::Details& rDetails,
+-                           BOOL bOnlyAcceptSingle )
++                           BOOL bOnlyAcceptSingle, ScAddress::ExternalInfo* pExtInfo )
+ {
+     const sal_Unicode* pTmp = NULL;
+     String aExternDocName, aStartTabName, aEndTabName;
+@@ -442,6 +439,18 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+ #endif
+     p = lcl_ScRange_Parse_XL_Header( r, p, pDoc,
+         aExternDocName, aStartTabName, aEndTabName, nFlags );
++
++    if (aExternDocName.Len() > 0)
++    {
++        ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++        if (pExtInfo && !pRefMgr->isOwnDocument(aExternDocName))
++        {
++            pExtInfo->mbExternal = true;
++            pExtInfo->maTabName = aStartTabName;
++            pExtInfo->mnFileId = pRefMgr->getExternalFileId(aExternDocName);
++        }
++    }
++
+     if( NULL == p )
+         return 0;
+ 
+@@ -480,8 +489,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+             r.aStart.SetCol( 0 );
+             r.aEnd.SetCol( MAXCOL );
+ 
+-            return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc,
+-                aExternDocName, aStartTabName, aEndTabName, nFlags );
++            return bOnlyAcceptSingle ? 0 : nFlags;
+         }
+         else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
+             goto failed;
+@@ -501,8 +509,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+                 return nFlags;
+             }
+ 
+-            return bOnlyAcceptSingle ? lcl_XL_LinkSheetRef( r, pDoc,
+-                aExternDocName, aStartTabName, aEndTabName, nFlags ) : 0;
++            return bOnlyAcceptSingle ? nFlags : 0;
+         }
+         p = pTmp;
+ 
+@@ -517,8 +524,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+         }
+ 
+         nFlags |= (nFlags2 << 4);
+-        return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return bOnlyAcceptSingle ? 0 : nFlags;
+     }
+     else if( *p == 'C' || *p == 'c' )   // full col C#
+     {
+@@ -550,8 +556,7 @@ lcl_ScRange_Parse_XL_R1C1( ScRange& r,
+         r.aStart.SetRow( 0 );
+         r.aEnd.SetRow( MAXROW );
+ 
+-        return bOnlyAcceptSingle ? 0 : lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return bOnlyAcceptSingle ? 0 : nFlags;
+     }
+ 
+ failed :
+@@ -604,7 +609,8 @@ static USHORT
+ lcl_ScRange_Parse_XL_A1( ScRange& r,
+                          const sal_Unicode* p,
+                          ScDocument* pDoc,
+-                         BOOL bOnlyAcceptSingle )
++                         BOOL bOnlyAcceptSingle,
++                         ScAddress::ExternalInfo* pExtInfo )
+ {
+     const sal_Unicode* tmp1, *tmp2;
+     String aExternDocName, aStartTabName, aEndTabName; // for external link table
+@@ -619,6 +625,18 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+ #endif
+     p = lcl_ScRange_Parse_XL_Header( r, p, pDoc,
+         aExternDocName, aStartTabName, aEndTabName, nFlags );
++
++    if (aExternDocName.Len() > 0)
++    {
++        ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++        if (pExtInfo && !pRefMgr->isOwnDocument(aExternDocName))
++        {
++            pExtInfo->mbExternal = true;
++            pExtInfo->maTabName = aStartTabName;
++            pExtInfo->mnFileId = pRefMgr->getExternalFileId(aExternDocName);
++        }
++    }
++
+     if( NULL == p )
+         return 0;
+ 
+@@ -640,8 +658,7 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+             SCA_VALID_COL | SCA_VALID_COL2 |
+             SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE;
+         nFlags |= (nFlags2 << 4);
+-        return lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return nFlags;
+     }
+ 
+     tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags );
+@@ -661,8 +678,7 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+             SCA_VALID_ROW | SCA_VALID_ROW2 |
+             SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE;
+         nFlags |= (nFlags2 << 4);
+-        return lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return nFlags;
+     }
+ 
+     // prepare as if it's a singleton, in case we want to fall back */
+@@ -672,8 +688,7 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+     if ( bOnlyAcceptSingle )
+     {
+         if ( *tmp2 == 0 )
+-            return lcl_XL_LinkSheetRef( r, pDoc,
+-                aExternDocName, aStartTabName, aEndTabName, nFlags );
++            return nFlags;
+         else
+         {
+             // any trailing invalid character must invalidate the address.
+@@ -692,12 +707,11 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+     p = tmp2;
+     tmp1 = lcl_a1_get_col( p+1, &r.aEnd, &nFlags2 );
+     if( !tmp1 ) // strange, but valid singleton
+-        return lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return nFlags;
++
+     tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
+     if( !tmp2 ) // strange, but valid singleton
+-        return lcl_XL_LinkSheetRef( r, pDoc,
+-            aExternDocName, aStartTabName, aEndTabName, nFlags );
++        return nFlags;
+ 
+     if ( *tmp2 != 0 )
+     {
+@@ -708,45 +722,31 @@ lcl_ScRange_Parse_XL_A1( ScRange& r,
+     }
+ 
+     nFlags |= (nFlags2 << 4);
+-    return lcl_XL_LinkSheetRef( r, pDoc,
+-        aExternDocName, aStartTabName, aEndTabName, nFlags );
++    return nFlags;
+ }
+ 
+ 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 )
+ {
+     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 #
+-    if ( *p == '\'' && ScGlobal::UnicodeStrChr( p, SC_COMPILER_FILE_TAB_SEP ) )
++    // Lets see if this is a reference to something in an external file.  A
++    // document name is always quoted and has a trailing #.
++    if (*p == '\'')
+     {
+-        const sal_Unicode *pStart = p;   
+-        BOOL bQuote = TRUE;         // A Documentname is always quoted
+-        aDocTab += *p++;
+-        while ( bQuote && *p )
+-        {
+-            if ( *p == '\'' && *(p-1) != '\\' )
+-                bQuote = FALSE;
+-            else if( !(*p == '\\' && *(p+1) == '\'') )
+-                aDocName += *p;     // An escaped Quote in the Documentname
+-            aDocTab += *p++;
+-        }
+-        aDocTab += *p;              // den SC_COMPILER_FILE_TAB_SEP mitnehmen
+-        if( *p++ == SC_COMPILER_FILE_TAB_SEP )
+-            bExtDoc = TRUE;
++        const sal_Unicode* pStart = p;
++        p = lcl_ParseQuotedName(p, aDocName);
++        if (*p++ == SC_COMPILER_FILE_TAB_SEP)
++            bExtDoc = true;
+         else
+-        {
+-            // It wasn't a document after all, reset and continue as normal
++            // This is not a document name.  Perhaps a quoted relative table 
++            // name.
+             p = pStart;
+-            aDocTab = String();
+-        }
+     }
+ 
+     SCCOL   nCol = 0;
+@@ -762,25 +762,11 @@ lcl_ScAddress_Parse_OOo( BOOL& bExternal, const sal_Unicode* p,
+         if (*p == '$')
+             nRes |= SCA_TAB_ABSOLUTE, p++;
+ 
+-        // Tokens that start at ' can have anything in them until a final '
+-        // but '' marks an escaped '
+-        // We've earlier guaranteed that a string containing '' will be
+-        // surrounded by '
+-        if( *p == '\'' )
+-        {
+-            ++p;
+-            while (*p)
+-            {
+-                if (*p == '\'')
+-                {
+-                    if ( (*(p+1) != '\'') )
+-                        break;
+-                    else
+-                        *p++;
+-                }
+-                aTab += *p++;
+-            }
+-        }
++        if (*p == '\'')
++            // Tokens that start at ' can have anything in them until a final
++            // ' but '' marks an escaped '.  We've earlier guaranteed that a
++            // string containing '' will be surrounded by '.
++            p = lcl_ParseQuotedName(p, aTab);
+ 
+         while (*p)
+         {
+@@ -795,35 +781,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 +846,31 @@ 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);
++
++        if (!pRefMgr->isOwnDocument(aDocName))
+         {
+-            nRes |= SCA_VALID_TAB;
++            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;
+         }
+-        else
+-            nRes = 0;   // #NAME? statt #REF!, Dateiname bleibt erhalten
+     }
++
+     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 +889,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,20 +900,20 @@ 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:
+         {
+             ScRange r = rAddr;
+-            USHORT nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, TRUE );
++            USHORT nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, TRUE, pExtInfo );
+             rAddr = r.aStart;
+             return nFlags;
+         }
+     case ScAddress::CONV_XL_R1C1:
+         {
+             ScRange r = rAddr;
+-            USHORT nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, TRUE );
++            USHORT nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, TRUE, pExtInfo );
+             rAddr = r.aStart;
+             return nFlags;
+         }
+@@ -949,9 +925,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 +963,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 +1034,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 +1047,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 +1105,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,13 +1114,13 @@ 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 );
++        return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, FALSE, pExtInfo );
+ 
+     case ScAddress::CONV_XL_R1C1:
+-        return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, FALSE );
++        return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, FALSE, pExtInfo );
+     }
+ }
+ 
+diff --git sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx
+index 918332d..d9b0549 100644
+--- sc/source/core/tool/compiler.cxx
++++ sc/source/core/tool/compiler.cxx
+@@ -74,9 +74,11 @@
+ #include "errorcodes.hxx"
+ #include "parclass.hxx"
+ #include "autonamecache.hxx"
++#include "externalrefmgr.hxx"
+ 
+ using namespace ::com::sun::star;
+ using rtl::OUString;
++using ::std::vector;
+ 
+ #if OSL_DEBUG_LEVEL > 1
+ // For some unknown reason the identical dbg_dump utilities in
+@@ -1191,7 +1193,7 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P
+                 {
+                     rRes.TokenType = KParseType::SINGLE_QUOTE_NAME;
+                     rRes.EndPos = nPos+1;
+-                    return false;
++                    return true;
+                 }
+                 ++nPos;
+             }
+@@ -1199,9 +1201,197 @@ static bool lcl_isValidQuotedText( const String& rFormula, xub_StrLen nSrcPos, P
+         }
+     }
+ 
++    return false;
++}
++
++static bool lcl_parseExternalName( const String& rSymbol, String& rFile, String& rName, const sal_Unicode cSep )
++{
++    const sal_Unicode* p = rSymbol.GetBuffer();
++    xub_StrLen nLen = rSymbol.Len();
++    sal_Unicode cPrev = 0;
++    String aTmpFile, aTmpName;
++    bool bInName = false;
++    for (xub_StrLen i = 0; i < nLen; ++i, ++p)
++    {
++        sal_Unicode c = *p;
++        if (i == 0)
++        {
++            if (c == '.' || c == cSep)
++                return false;
++
++            if (c == '\'')
++            {
++                // Move to the next chart and loop until the second single
++                // quote.
++                cPrev = c;
++                ++i; ++p;
++                for (xub_StrLen j = i; j < nLen; ++j, ++p)
++                {
++                    c = *p;
++                    if (c == '\'')
++                    {
++                        if (j == i)
++                        {    
++                            // empty quote e.g. (=''!Name)
++                            return false;
++                        }
++
++                        if (cPrev == '\'')
++                        {
++                            // two consecutive quotes equals a single
++                            // quote in the file name.
++                            aTmpFile.Append(c);
++                            cPrev = 'a';
++                        }
++                        else
++                            cPrev = c;
++
++                        continue;
++                    }
++
++                    if (cPrev == '\'' && j != i)
++                    {
++                        // this is not a quote but the previous one
++                        // is.  This ends the parsing of the quoted
++                        // segment.
++
++                        i = j;
++                        bInName = true;
++                        break;
++                    }
++                    aTmpFile.Append(c);
++                    cPrev = c;
++                }
++
++                if (!bInName)
++                {    
++                    // premature ending of the quoted segment.
++                    return false;
++                }
++
++                if (c != cSep)
++                {    
++                    // only the separator is allowed after the closing quote.
++                    return false;
++                }
++
++                cPrev = c;
++                continue;
++            }
++        }
++
++        if (bInName)
++        {
++            if (c == cSep)
++            {
++                // A second separator ?  Not a valid external name.
++                return false;
++            }
++            aTmpName.Append(c);
++        }
++        else
++        {
++            if (c == cSep)
++            {
++                bInName = true;
++            }
++            else
++            {
++                do
++                {
++                    if (CharClass::isAsciiAlphaNumeric(c))
++                        // allowed.
++                        break;
++
++                    if (c > 128)
++                        // non-ASCII character is allowed.
++                        break;
++
++                    bool bValid = false;
++                    switch (c)
++                    {
++                        case '_':
++                        case '-':
++                        case '.':
++                            // these special characters are allowed.
++                            bValid = true;
++                            break;
++                    }
++                    if (bValid)
++                        break;
++
++                    return false;
++                }
++                while (false);
++                aTmpFile.Append(c);
++            }
++        }
++        cPrev = c;
++    }
++
++    if (!bInName)
++    {
++        // No name found - most likely the symbol has no '!'s.
++        return false;
++    }
++
++    rFile = aTmpFile;
++    rName = aTmpName;
++    return true;
++}
++
++static String lcl_makeExternalNameStr( const String& rFile, const String& rName, const sal_Unicode cSep )
++{
++    String aStr, aFile = rFile;
++    aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
++    aStr.Append(sal_Unicode('\''));
++    aStr.Append(aFile);
++    aStr.Append(sal_Unicode('\''));
++    aStr.Append(cSep);
++    aStr.Append(rName);
++    return aStr;
++}
++
++static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1, 
++                                const vector<String>& rTabNames, const ComplRefData& rRef )
++{
++    SCsTAB nTabSpan = rRef.Ref2.nTab - rRef.Ref1.nTab;
++    if (nTabSpan > 0)
++    {
++        size_t nCount = rTabNames.size();
++        vector<String>::const_iterator itrBeg = rTabNames.begin(), itrEnd = rTabNames.end();
++        vector<String>::const_iterator itr = ::std::find(itrBeg, itrEnd, rTabName1);
++        if (itr == rTabNames.end())
++        {
++            rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
++            return false;    
++        }
++
++        size_t nDist = ::std::distance(itrBeg, itr);
++        if (nDist + static_cast<size_t>(nTabSpan) >= nCount)
++        {
++            rTabName2 = ScGlobal::GetRscString(STR_NO_REF_TABLE);
++            return false;
++        }
++
++        rTabName2 = rTabNames[nDist+nTabSpan];
++    }
++    else
++        rTabName2 = rTabName1;
++
+     return true;
+ }
+ 
++static void lcl_appendTabName(::rtl::OUStringBuffer& rBuffer, const String& rTabName)
++{
++    bool bQuote = (rTabName.Search(sal_Unicode(' '), 0) != STRING_NOTFOUND);
++    if (bQuote)
++        rBuffer.append(sal_Unicode('\''));
++    rBuffer.append(rTabName);
++    if (bQuote)
++        rBuffer.append(sal_Unicode('\''));
++}
++
+ struct Convention_A1 : public ScCompiler::Convention
+ {
+     Convention_A1( ScAddress::Convention eConv ) : ScCompiler::Convention( eConv ) { }
+@@ -1215,14 +1405,14 @@ struct Convention_A1 : public ScCompiler::Convention
+                                const CharClass* pCharClass) const
+     {
+         ParseResult aRet;
+-        if ( !lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
++        if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+             return aRet;
+ 
+         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+             KParseTokens::ASC_UNDERSCORE | KParseTokens::ASC_DOLLAR;
+         static const sal_Int32 nContFlags = nStartFlags | KParseTokens::ASC_DOT;
+         // '?' allowed in range names because of Xcl :-/
+-        static const String aAddAllowed( '?' );
++        static const String aAddAllowed(String::CreateFromAscii("?#"));
+         return pCharClass->parseAnyToken( rFormula,
+                 nSrcPos, nStartFlags, aAddAllowed, nContFlags, aAddAllowed );
+     }
+@@ -1405,6 +1595,86 @@ struct ConventionOOO_A1 : public Convention_A1
+ 
+         return sal_Unicode(0);
+     }
++
++    virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName ) const
++    {
++        return lcl_parseExternalName(rSymbol, rFile, rName, sal_Unicode('#'));
++    }
++
++    virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
++    {
++        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('$'));
++            lcl_appendTabName(rBuffer, rTabName);
++
++            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(':'));
++
++        // Get the name of the last table.
++        const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++        if (!pTabNames)
++            return;
++
++        String aLastTabName;
++        if (!lcl_getLastTabName(aLastTabName, rTabName, *pTabNames, aRef))
++        {
++            rBuffer.append(aLastTabName);
++            return;
++        }
++        makeExternalSingleRefStr(rBuffer, nFileId, aLastTabName, aRef.Ref2, pRefMgr, (aRef.Ref1.nTab != aRef.Ref2.nTab));
++    }
+ };
+ 
+ 
+@@ -1526,11 +1796,128 @@ struct ConventionXL
+         }
+         return sal_Unicode(0);
+     }
++
++    static bool parseExternalName( const String& rSymbol, String& rFile, String& rName )
++    {
++        return lcl_parseExternalName(rSymbol, rFile, rName, sal_Unicode('!'));
++    }
++
++    static String makeExternalNameStr( const String& rFile, const String& rName )
++    {
++        return lcl_makeExternalNameStr(rFile, rName, sal_Unicode('!'));
++    }
++
++    static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName )
++    {
++        // Format that is easier to deal with inside OOo, because we use file 
++        // URL, and all characetrs are allowed.  Check if it makes sense to do
++        // it the way Gnumeric does it.  Gnumeric doesn't use the URL form
++        // and allows relative file path.
++        // 
++        //   ['file:///path/to/source/filename.xls']
++
++        rBuffer.append(sal_Unicode('['));
++        rBuffer.append(sal_Unicode('\''));
++        const sal_Unicode* pBuf = rFullName.GetBuffer();
++        xub_StrLen nLen = rFullName.Len();
++        for (xub_StrLen i = 0; i < nLen; ++i)
++        {
++            const sal_Unicode c = pBuf[i];
++            if (c == sal_Unicode('\''))
++                rBuffer.append(c);
++            rBuffer.append(c);
++        }
++        rBuffer.append(sal_Unicode('\''));
++        rBuffer.append(sal_Unicode(']'));
++    }
++
++    static void makeExternalTabNameRange( ::rtl::OUStringBuffer& rBuf, const String& rTabName, 
++                                          const vector<String>& rTabNames,
++                                          const ComplRefData& rRef )
++    {
++        String aLastTabName;
++        if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
++        {
++            rBuf.append(aLastTabName);   
++            return;
++        }
++
++        lcl_appendTabName(rBuf, rTabName);
++        if (rTabName != aLastTabName)
++        {
++            rBuf.append(sal_Unicode(':'));
++            lcl_appendTabName(rBuf, aLastTabName);
++        }
++    }
++
++    static void parseExternalDocName( const String& rFormula, xub_StrLen& rSrcPos )
++    {
++        xub_StrLen nLen = rFormula.Len();
++        const sal_Unicode* p = rFormula.GetBuffer();
++        sal_Unicode cPrev = 0;
++        for (xub_StrLen i = rSrcPos; i < nLen; ++i)
++        {
++            sal_Unicode c = p[i];
++            if (i == rSrcPos)
++            {
++                // first character must be '['.
++                if (c != '[')
++                    return;
++            }
++            else if (i == rSrcPos + 1)
++            {
++                // second character must be a single quote.
++                if (c != '\'')
++                    return;
++            }
++            else if (c == '\'')
++            {
++                if (cPrev == '\'')
++                    // two successive single quote is treated as a single 
++                    // valid character.
++                    c = 'a';
++            }
++            else if (c == ']')
++            {
++                if (cPrev == '\'')
++                {
++                    // valid source document path found.  Increment the
++                    // current position to skip the source path.
++                    rSrcPos = i + 1;
++                    if (rSrcPos >= nLen)
++                        rSrcPos = nLen - 1;
++                    return;
++                }
++                else
++                    return;
++            }
++            else
++            {
++                // any other character
++                if (i > rSrcPos + 2 && cPrev == '\'')
++                    // unless it's the 3rd character, a normal character 
++                    // following immediately a single quote is invalid.
++                    return;
++            }
++            cPrev = c;
++        }
++    }
+ };
+ 
+ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+ {
+     ConventionXL_A1() : Convention_A1( ScAddress::CONV_XL_A1 ) { }
++
++    void makeSingleCellStr( ::rtl::OUStringBuffer& rBuf, const SingleRefData& rRef ) const
++    {
++        if (!rRef.IsColRel())
++            rBuf.append(sal_Unicode('$'));
++        MakeColStr(rBuf, rRef.nCol);
++        if (!rRef.IsRowRel())
++            rBuf.append(sal_Unicode('$'));
++        MakeRowStr(rBuf, rRef.nRow);
++    }
++
+     void MakeRefStr( rtl::OUStringBuffer&   rBuf,
+                      const ScCompiler&      rComp,
+                      const ComplRefData& rRef,
+@@ -1584,22 +1971,11 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+             }
+         }
+ 
+-        if (!aRef.Ref1.IsColRel())
+-            rBuf.append(sal_Unicode('$'));
+-        MakeColStr(rBuf, aRef.Ref1.nCol );
+-        if (!aRef.Ref1.IsRowRel())
+-            rBuf.append(sal_Unicode('$'));
+-        MakeRowStr( rBuf, aRef.Ref1.nRow );
+-
++        makeSingleCellStr(rBuf, aRef.Ref1);
+         if (!bSingleRef)
+         {
+             rBuf.append(sal_Unicode( ':' ));
+-            if (!aRef.Ref2.IsColRel())
+-                rBuf.append(sal_Unicode('$'));
+-            MakeColStr(rBuf, aRef.Ref2.nCol );
+-            if (!aRef.Ref2.IsRowRel())
+-                rBuf.append(sal_Unicode('$'));
+-            MakeRowStr( rBuf, aRef.Ref2.nRow );
++            makeSingleCellStr(rBuf, aRef.Ref2);
+         }
+     }
+ 
+@@ -1607,8 +1983,10 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+                                        xub_StrLen nSrcPos,
+                                        const CharClass* pCharClass) const
+     {
++        ConventionXL::parseExternalDocName(rFormula, nSrcPos);
++
+         ParseResult aRet;
+-        if ( !lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
++        if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+             return aRet;
+ 
+         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+@@ -1624,6 +2002,67 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
+     {
+         return ConventionXL::getSpecialSymbol(eSymType);
+     }
++
++    virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName ) const
++    {
++        return ConventionXL::parseExternalName(rSymbol, rFile, rName);
++    }
++
++    virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
++    {
++        return ConventionXL::makeExternalNameStr(rFile, rName);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
++        // This is a little different from the format Excel uses, as Excel
++        // puts [] only around the file name.  But we need to enclose the
++        // whole file path with [] because the file name can contain any 
++        // characters.
++
++        const String* pFullName = pRefMgr->getExternalFileName(nFileId);
++        if (!pFullName)
++            return;
++
++        SingleRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
++        lcl_appendTabName(rBuffer, rTabName);
++        rBuffer.append(sal_Unicode('!'));
++
++        makeSingleCellStr(rBuffer, aRef);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        const String* pFullName = pRefMgr->getExternalFileName(nFileId);
++        if (!pFullName)
++            return;
++
++        const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++        if (!pTabNames)
++            return;
++
++        ComplRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
++        ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, *pTabNames, aRef);
++        rBuffer.append(sal_Unicode('!'));
++
++        makeSingleCellStr(rBuffer, aRef.Ref1);
++        if (aRef.Ref1 != aRef.Ref2)
++        {
++            rBuffer.append(sal_Unicode(':'));
++            makeSingleCellStr(rBuffer, aRef.Ref2);
++        }
++    }
+ };
+ 
+ static const ConventionXL_A1 ConvXL_A1;
+@@ -1733,8 +2172,10 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
+                                xub_StrLen nSrcPos,
+                                const CharClass* pCharClass) const
+     {
++        ConventionXL::parseExternalDocName(rFormula, nSrcPos);
++
+         ParseResult aRet;
+-        if ( !lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
++        if ( lcl_isValidQuotedText(rFormula, nSrcPos, aRet) )
+             return aRet;
+ 
+         static const sal_Int32 nStartFlags = KParseTokens::ANY_LETTER_OR_NUMBER |
+@@ -1751,6 +2192,95 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
+     {
+         return ConventionXL::getSpecialSymbol(eSymType);
+     }
++
++    virtual bool parseExternalName( const String& rSymbol, String& rFile, String& rName ) const
++    {
++        return ConventionXL::parseExternalName(rSymbol, rFile, rName);
++    }
++
++    virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
++    {
++        return ConventionXL::makeExternalNameStr(rFile, rName);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
++        // This is a little different from the format Excel uses, as Excel
++        // puts [] only around the file name.  But we need to enclose the
++        // whole file path with [] because the file name can contain any 
++        // characters.
++
++        const String* pFullName = pRefMgr->getExternalFileName(nFileId);
++        if (!pFullName)
++            return;
++
++        SingleRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
++        lcl_appendTabName(rBuffer, rTabName);
++        rBuffer.append(sal_Unicode('!'));
++
++        r1c1_add_row(rBuffer, aRef);
++        r1c1_add_col(rBuffer, aRef);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        const String* pFullName = pRefMgr->getExternalFileName(nFileId);
++        if (!pFullName)
++            return;
++
++        const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++        if (!pTabNames)
++            return;
++
++        ComplRefData aRef(rRef);
++        aRef.CalcAbsIfRel(rCompiler.GetPos());
++
++        ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
++        ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, *pTabNames, aRef);
++        rBuffer.append(sal_Unicode('!'));
++
++        if (aRef.Ref2.IsColDeleted() || aRef.Ref2.IsRowDeleted())
++        {
++            rBuffer.append(ScGlobal::GetRscString(STR_NO_REF_TABLE));
++            return;
++        }
++
++        if (aRef.Ref1.nCol == 0 && aRef.Ref2.nCol >= MAXCOL)
++        {
++            r1c1_add_row(rBuffer, rRef.Ref1);
++            if (rRef.Ref1.nRow != rRef.Ref2.nRow || rRef.Ref1.IsRowRel() != rRef.Ref2.IsRowRel())
++            {
++                rBuffer.append (sal_Unicode(':'));
++                r1c1_add_row(rBuffer, rRef.Ref2);
++            }
++            return;
++        }
++
++        if (aRef.Ref1.nRow == 0 && aRef.Ref2.nRow >= MAXROW)
++        {
++            r1c1_add_col(rBuffer, aRef.Ref1);
++            if (aRef.Ref1.nCol != aRef.Ref2.nCol || aRef.Ref1.IsColRel() != aRef.Ref2.IsColRel())
++            {
++                rBuffer.append (sal_Unicode(':'));
++                r1c1_add_col(rBuffer, aRef.Ref2);
++            }
++            return;
++        }
++
++        r1c1_add_row(rBuffer, aRef.Ref1);
++        r1c1_add_col(rBuffer, aRef.Ref1);
++        rBuffer.append (sal_Unicode (':'));
++        r1c1_add_row(rBuffer, aRef.Ref2);
++        r1c1_add_col(rBuffer, aRef.Ref2);
++    }
+ };
+ 
+ static const ConventionXL_R1C1 ConvXL_R1C1;
+@@ -2208,7 +2738,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+                     static const int kQuote = kInc * 2;
+                     static const int kPast = kInc * 3;
+                     bool bAddToSymbol = true;
+-                    if ('.' == c && nRefInSheetName == 0)
++                    if (cSheetSep == c && nRefInSheetName == 0)
+                     {
+                         // eat it, no sheet name
+                         bAddToSymbol = false;
+@@ -2223,7 +2753,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray)
+                     }
+                     else if (nRefInSheetName < kPast)
+                     {
+-                        if ('$' == c && nRefInSheetName < kDollar)
++                        if (cSheetPrefix == c && nRefInSheetName < kDollar)
+                             nRefInSheetName += kDollar;
+                         else if ('\'' == c)
+                         {
+@@ -2545,7 +3075,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;
+@@ -2564,7 +3095,14 @@ 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();
+     }
+ 
+@@ -2576,7 +3114,8 @@ BOOL ScCompiler::IsSingleReference( const String& rName )
+ {
+     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 ) )
+@@ -2600,7 +3139,11 @@ BOOL ScCompiler::IsSingleReference( const String& rName )
+             nFlags |= SCA_VALID;
+         }
+         aRef.CalcRelFromAbs( aPos );
+-        aToken.SetSingleReference( aRef );
++
++        if (aExtInfo.mbExternal)
++            aToken.SetExternalSingleRef(aExtInfo.mnFileId, aExtInfo.maTabName, aRef);
++        else
++            aToken.SetSingleReference(aRef);
+         pRawToken = aToken.Clone();
+     }
+ 
+@@ -2708,6 +3251,27 @@ BOOL ScCompiler::IsNamedRange( const String& rUpperName )
+         return FALSE;
+ }
+ 
++bool ScCompiler::IsExternalNamedRange( const String& rSymbol )
++{
++    if (!pConv)
++        return false;
++
++    String aFile, aName;
++    if (!pConv->parseExternalName(rSymbol, aFile, aName))
++        return false;
++
++    ScRawToken aToken;
++    if (aFile.Len() > MAXSTRLEN || aName.Len() > MAXSTRLEN)
++        return false;
++
++    ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++    pRefMgr->convertToAbsName(aFile);
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFile);
++    aToken.SetExternalName(nFileId, aName);
++    pRawToken = aToken.Clone();
++    return true;
++}
++
+ BOOL ScCompiler::IsDBRange( const String& rName )
+ {
+     USHORT n;
+@@ -3243,7 +3807,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
+         if (mnPredetectedReference)
+         {
+             String aStr( cSymbol);
+-            if (!IsPredetectedReference( aStr))
++            if (!IsPredetectedReference( aStr) && !IsExternalNamedRange( aStr))
+             {
+                 /* TODO: it would be nice to generate a #REF! error here, which
+                  * would need an ocBad token with additional error value.
+@@ -3306,6 +3870,7 @@ BOOL ScCompiler::NextNewToken( bool bInArray )
+               && !(bAllowBooleans && IsBoolean( aUpper ))
+               && !IsValue( aUpper )
+               && !IsNamedRange( aUpper )
++              && !IsExternalNamedRange(aOrg)
+               && !IsDBRange( aUpper )
+               && !IsColRowName( aUpper )
+               && !(bMayBeFuncName && IsMacro( aUpper ))
+@@ -3641,6 +4206,66 @@ BOOL ScCompiler::GetToken()
+     }
+     if( pToken->GetOpCode() == ocSubTotal )
+         glSubTotal = TRUE;
++    else if ( pToken->GetOpCode() == ocExternalName )
++    {
++        // Handle external single and double references, or names.
++
++        ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++        const String* pFile = pRefMgr->getExternalFileName(pToken->GetIndex());
++        if (!pFile)
++            SetError(errNoName);
++
++        switch (pToken->GetType())
++        {
++            case svExternalName:
++            {
++                const String& rName = pToken->GetString();
++                ScTokenArray* pNew = pRefMgr->getRangeNameTokens(pToken->GetIndex(), rName, &aPos);
++                if (pNew)
++                {
++                    PushTokenArray(pNew->Clone(), true);
++                    return GetToken();
++                }
++            }
++            break;
++            case svSingleRef:
++            {
++                SingleRefData aData(pToken->GetSingleRef());
++                if (aData.IsTabRel())
++                    // external single reference must have an absolute table reference!
++                    break;
++
++                aData.CalcAbsIfRel(aPos);
++                ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
++                ScToken* pNew = pRefMgr->getSingleRefToken(pToken->GetIndex(), pToken->GetString(), aAddr, &aPos, NULL);
++                if (pNew)
++                {
++                    pToken = pNew->Clone();
++                    return true;
++                }
++            }
++            break;
++            case svDoubleRef:
++            {
++                ComplRefData aData(pToken->GetDoubleRef());
++                if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
++                    // external double reference must have an absolute table reference!
++                    break;
++
++                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(), pToken->GetString(), aRange, &aPos);
++                if (pNew)
++                {
++                    PushTokenArray(pNew->Clone(), true);
++                    return GetToken();
++                }
++            }
++            break;
++        }
++        SetError(errNoName);
++    }
+     else if( pToken->GetOpCode() == ocName )
+     {
+         ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
+@@ -5638,111 +6263,140 @@ 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 )
++            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/refdata.cxx sc/source/core/tool/refdata.cxx
+index 4ac1814..7ec74d8 100644
+--- sc/source/core/tool/refdata.cxx
++++ sc/source/core/tool/refdata.cxx
+@@ -200,6 +200,10 @@ BOOL SingleRefData::operator==( const SingleRefData& r ) const
+         (Flags.bTabRel ? nRelTab == r.nRelTab : nTab == r.nTab);
+ }
+ 
++bool SingleRefData::operator!=( const SingleRefData& r ) const
++{
++    return !operator==(r);
++}
+ 
+ static void lcl_putInOrder( SingleRefData & rRef1, SingleRefData & rRef2 )
+ {
+diff --git sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx
+index a20cbd5..51611ef 100644
+--- sc/source/core/tool/token.cxx
++++ sc/source/core/tool/token.cxx
+@@ -54,6 +54,8 @@
+ #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,48 @@ 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();
++    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));
++    extname.cName[n] = 0;
++}
++
+ ComplRefData& ScRawToken::GetReference()
+ {
+     DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "GetReference: no Ref" );
+@@ -260,22 +304,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 +367,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 +393,11 @@ ScToken* ScRawToken::CreateToken() const
+         case svIndex :
+             return new ScIndexToken( eOp, nIndex );
+         //break;
++        case svExternalName:
++        {
++            String aName(extname.cName);
++            return new ScExternalNameToken( extname.nFileId, aName );
++        }
+         case svJump :
+             return new ScJumpToken( eOp, (short*) nJump );
+         //break;
+@@ -478,6 +549,7 @@ BOOL ScToken::IsMatrixFunction() const
+ 
+ ScToken* ScToken::Clone() const
+ {
++    OpCode nOp = GetOpCode();
+     switch ( GetType() )
+     {
+         case svByte :
+@@ -487,20 +559,24 @@ ScToken* ScToken::Clone() const
+             return new ScDoubleToken( *static_cast<const ScDoubleToken*>(this) );
+         //break;
+         case svString :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScStringToken( *static_cast<const ScStringToken*>(this) );
+             else
+                 return new ScStringOpToken( *static_cast<const ScStringOpToken*>(this) );
+         //break;
+         case svSingleRef :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScSingleRefToken( *static_cast<const ScSingleRefToken*>(this) );
++            else if (nOp == ocExternalName)
++                return new ScExternalSingleRefToken( *static_cast<const ScExternalSingleRefToken*>(this) );
+             else
+                 return new ScSingleRefOpToken( *static_cast<const ScSingleRefOpToken*>(this) );
+         //break;
+         case svDoubleRef :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScDoubleRefToken( *static_cast<const ScDoubleRefToken*>(this) );
++            else if (nOp == ocExternalName)
++                return new ScExternalDoubleRefToken( *static_cast<const ScExternalDoubleRefToken*>(this) );
+             else
+                 return new ScDoubleRefOpToken( *static_cast<const ScDoubleRefOpToken*>(this) );
+         //break;
+@@ -522,6 +598,9 @@ ScToken* ScToken::Clone() const
+         case svExternal :
+             return new ScExternalToken( *static_cast<const ScExternalToken*>(this) );
+         //break;
++        case svExternalName :
++            return new ScExternalNameToken( *static_cast<const ScExternalNameToken*>(this) );
++        //break;
+         case svFAP :
+             return new ScFAPToken( *static_cast<const ScFAPToken*>(this) );
+         //break;
+@@ -660,6 +739,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 +751,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 +777,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 +1121,190 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
+     return ScToken::operator==( r ) && nIndex == r.GetIndex();
+ }
+ 
++// ============================================================================
++
++ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& r ) :
++    ScOpToken(ocExternalName, svSingleRef),
++    mnFileId(nFileId),
++    maTabName(rTabName),
++    maSingleRef(r)
++{
++}
++
++ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) :
++    ScOpToken(r), 
++    mnFileId(r.mnFileId),
++    maTabName(r.maTabName),
++    maSingleRef(r.maSingleRef)
++{
++}
++
++ScExternalSingleRefToken::~ScExternalSingleRefToken()
++{
++}
++
++USHORT ScExternalSingleRefToken::GetIndex() const
++{
++    return mnFileId;
++}
++
++const String& ScExternalSingleRefToken::GetString() const
++{
++    return maTabName;
++}
++
++const SingleRefData& ScExternalSingleRefToken::GetSingleRef() const
++{
++    return maSingleRef;
++}
++
++SingleRefData& ScExternalSingleRefToken::GetSingleRef()
++{
++    return maSingleRef;
++}
++
++BOOL ScExternalSingleRefToken::operator ==( const ScToken& r ) const
++{
++    if (!ScToken::operator==(r))
++        return false;
++
++    if (mnFileId != r.GetIndex())
++        return false;
++
++    if (maTabName != r.GetString())
++        return false;
++
++    return maSingleRef == r.GetSingleRef();
++}
++
++// ============================================================================
++
++ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& r ) :
++    ScOpToken(ocExternalName, svDoubleRef),
++    mnFileId(nFileId),
++    maTabName(rTabName),
++    maDoubleRef(r)
++{
++}
++
++ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) :
++    ScOpToken(r), 
++    mnFileId(r.mnFileId),
++    maTabName(r.maTabName),
++    maDoubleRef(r.maDoubleRef)
++{
++}
++
++ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
++{
++}
++
++USHORT ScExternalDoubleRefToken::GetIndex() const
++{
++    return mnFileId;
++}
++
++const String& ScExternalDoubleRefToken::GetString() const
++{
++    return maTabName;
++}
++
++const SingleRefData& ScExternalDoubleRefToken::GetSingleRef() const
++{
++    return maDoubleRef.Ref1;
++}
++
++SingleRefData& ScExternalDoubleRefToken::GetSingleRef()
++{
++    return maDoubleRef.Ref1;
++}
++
++const SingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const
++{
++    return maDoubleRef.Ref2;
++}
++
++SingleRefData& ScExternalDoubleRefToken::GetSingleRef2()
++{
++    return maDoubleRef.Ref2;
++}
++
++const ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() const
++{
++    return maDoubleRef;
++}
++
++ComplRefData& ScExternalDoubleRefToken::GetDoubleRef()
++{
++    return maDoubleRef;
++}
++
++BOOL ScExternalDoubleRefToken::operator ==( const ScToken& r ) const
++{
++    if (!ScToken::operator==(r))
++        return false;
++
++    if (mnFileId != r.GetIndex())
++        return false;
++
++    if (maTabName != r.GetString())
++        return false;
++
++    return maDoubleRef == r.GetDoubleRef();
++}
++
++// ============================================================================
++
++ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
++    ScOpToken(ocExternalName, svExternalName),
++    mnFileId(nFileId),
++    maName(rName)
++{
++}
++
++ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) :
++    ScOpToken(r),
++    mnFileId(r.mnFileId),
++    maName(r.maName)
++{
++}
++
++ScExternalNameToken::~ScExternalNameToken() {}
++
++USHORT ScExternalNameToken::GetIndex() const
++{
++    return mnFileId;
++}
++
++const String& ScExternalNameToken::GetString() const
++{
++    return maName;
++}
++
++BOOL ScExternalNameToken::operator==( const ScToken& r ) const
++{
++    if ( !ScToken::operator==(r) )
++        return false;
++
++    if (mnFileId != r.GetIndex())
++        return false;
++
++    xub_StrLen nLen = maName.Len();
++    const String& rName = r.GetString();
++    if (nLen != rName.Len())
++        return false;
++
++    const sal_Unicode* p1 = maName.GetBuffer();
++    const sal_Unicode* p2 = rName.GetBuffer();
++    for (xub_StrLen j = 0; j < nLen; ++j)
++    {
++        if (p1[j] != p2[j])
++            return false;
++    }
++    return true;
++}
++
++// ============================================================================
+ 
+ short* ScJumpToken::GetJump() const                     { return pJump; }
+ BOOL ScJumpToken::operator==( const ScToken& r ) const
+@@ -1237,6 +1507,9 @@ ScToken* ScTokenArray::GetNextReferenceOrName()
+ {
+     for( ScToken* t = Next(); t; t = Next() )
+     {
++        if ( t->GetOpCode() == ocExternalName )
++            return t;
++
+         switch( t->GetType() )
+         {
+             case svSingleRef:
+@@ -1893,6 +2166,21 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
+     return Add( new ScMatrixToken( p ) );
+ }
+ 
++ScToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName )
++{
++    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/excform.cxx sc/source/filter/excel/excform.cxx
+index 3070f34..fd87dbf 100644
+--- sc/source/filter/excel/excform.cxx
++++ sc/source/filter/excel/excform.cxx
+@@ -46,6 +46,7 @@
+ #include "xilink.hxx"
+ #include "xiname.hxx"
+ 
++using ::std::vector;
+ 
+ const UINT16 ExcelToSc::nRowMask = 0x3FFF;
+ const UINT16 ExcelToSc::nLastInd = 399;
+@@ -1329,6 +1330,13 @@ ConvErr ExcelToSc::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal
+ 	return eRet;
+ }
+ 
++ConvErr ExcelToSc::ConvertExternName( const ScTokenArray*& /*rpArray*/, XclImpStream& /*rStrm*/, sal_Size /*nFormulaLen*/,
++                                      const String& /*rUrl*/, const vector<String>& /*rTabNames*/ )
++{
++    // not implemented ...
++    return ConvErrNi;
++}
++
+ BOOL ExcelToSc::GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen )
+ {
+     DBG_ASSERT_BIFF( GetBiff() == EXC_BIFF5 );
+diff --git sc/source/filter/excel/excform8.cxx sc/source/filter/excel/excform8.cxx
+index ebf8543..e0467a0 100644
+--- sc/source/filter/excel/excform8.cxx
++++ sc/source/filter/excel/excform8.cxx
+@@ -41,6 +41,18 @@
+ #include "xilink.hxx"
+ #include "xiname.hxx"
+ 
++#include "externalrefmgr.hxx"
++
++#include <vector>
++
++using ::std::vector;
++
++ExcelToSc8::ExternalTabInfo::ExternalTabInfo() : 
++    mnFileId(0), mbExternal(false)
++{
++}
++
++// ============================================================================
+ 
+ ExcelToSc8::ExcelToSc8( const XclImpRoot& rRoot ) :
+     ExcelToSc( rRoot ),
+@@ -53,15 +65,33 @@ ExcelToSc8::~ExcelToSc8()
+ {
+ }
+ 
++bool ExcelToSc8::GetExternalFileIdFromXti( UINT16 nIxti, sal_uInt16& rFileId ) const
++{
++    const String* pFileUrl = rLinkMan.GetSupbookUrl(nIxti);
++    if (!pFileUrl || pFileUrl->Len() == 0)
++        return false;
++
++    String aFileUrl = ScGlobal::GetAbsDocName(*pFileUrl, GetDocShell());
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    rFileId = pRefMgr->getExternalFileId(aFileUrl);
+ 
+-BOOL ExcelToSc8::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab )
++    return true;
++}
++
++bool ExcelToSc8::Read3DTabReference( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo )
+ {
+ 	rFirstTab = rLastTab = 0;
++    rExtInfo.mbExternal = !rLinkMan.IsSelfRef(nIxti);
++    bool bSuccess = rLinkMan.GetScTabRange(rFirstTab, rLastTab, nIxti);
++    if (!bSuccess)
++        return false;
+ 
+-	UINT16 nIxti;
+-    rStrm >> nIxti;
++    if (!rExtInfo.mbExternal)
++        // This is internal reference.  Stop here.
++        return true;
+ 
+-    return rLinkMan.GetScTabRange( rFirstTab, rLastTab, nIxti );
++    rExtInfo.maTabName = rLinkMan.GetSupbookTabName(nIxti, rFirstTab);
++    return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId);
+ }
+ 
+ 
+@@ -608,8 +638,15 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+                     {
+                         case xlExtName:
+                         {
+-                            aStack << aPool.Store( ocNoName, pExtName->GetName() );
+-                            GetTracer().TraceFormulaExtName();
++                            sal_uInt16 nFileId;
++                            if (!GetExternalFileIdFromXti(nXtiIndex, nFileId))
++                            {
++                                aStack << aPool.Store(ocNoName, pExtName->GetName());
++                                break;
++                            }
++
++                            aStack << aPool.StoreExtName(nFileId, pExtName->GetName());
++                            pExtName->CreateExtNameData(GetDoc(), nFileId);
+                         }
+                         break;
+ 
+@@ -657,47 +694,67 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+ 			case 0x7C:
+ 			case 0x3C: // Deleted 3-D Cell Reference			[    277]
+ 			{
+-				UINT16 nRw, nGrbitCol;
++				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 );
++                ExternalTabInfo aExtInfo;
++                if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo))
++                {
++                    aPool << ocBad;
++                    aPool >> aStack;
++                    break;
++                }
+ 
+-                    ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
++                aSRD.nTab = nTabFirst;
++                aSRD.SetFlag3D( TRUE );
++                aSRD.SetTabRel( FALSE );
+ 
+-					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 );
++                ExcRelToScRel8( nRw, nGrbitCol, aSRD, bRangeName );
+ 
+-					if( nTabLast != nTabFirst )
+-					{
+-						aCRD.Ref1 = aCRD.Ref2 = aSRD;
+-						aCRD.Ref2.nTab = nTabLast;
++                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 (aExtInfo.mbExternal)
++                {
++                    // 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.
++
++                    if (nTabLast != nTabFirst)
++                    {
++                        aCRD.Ref1 = aCRD.Ref2 = aSRD;
++                        aCRD.Ref2.nTab = nTabLast;
++                        aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
++                    }
++                    else
++                        aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, 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 +764,61 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
+ 			case 0x7D:
+ 			case 0x3D: // Deleted 3-D Area Reference			[    277]
+ 			{
+-				UINT16 nRw1, nGrbitCol1, nRw2, nGrbitCol2;
++				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 )
+-				{
+-					SingleRefData	&rR1 = aCRD.Ref1;
+-					SingleRefData	&rR2 = aCRD.Ref2;
+-
+-					rR1.nTab = nTabFirst;
+-					rR2.nTab = nTabLast;
+-                    rR1.SetFlag3D( TRUE );
+-					rR1.SetTabRel( FALSE );
+-                    rR2.SetFlag3D( nTabFirst != nTabLast );
+-					rR2.SetTabRel( FALSE );
+-
+-                    ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
+-                    ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
+-
+-					if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
+-						SetComplCol( aCRD );
+-					else if( IsComplRowRange( nRw1, nRw2 ) )
+-						SetComplRow( aCRD );
+-
+-					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 );
+-
+-					aStack << aPool.Store( aCRD );
+-				}
+-				else
++                ExternalTabInfo aExtInfo;
++                if (!Read3DTabReference(nIxti, nTabFirst, nTabLast, aExtInfo))
+ 				{
+ 					aPool << ocBad;
+ 					aPool >> aStack;
++                    break;
+ 				}
++                
++                SingleRefData	&rR1 = aCRD.Ref1;
++                SingleRefData	&rR2 = aCRD.Ref2;
++
++                rR1.nTab = nTabFirst;
++                rR2.nTab = nTabLast;
++                rR1.SetFlag3D( TRUE );
++                rR1.SetTabRel( FALSE );
++                rR2.SetFlag3D( nTabFirst != nTabLast );
++                rR2.SetTabRel( FALSE );
++
++                ExcRelToScRel8( nRw1, nGrbitCol1, aCRD.Ref1, bRangeName );
++                ExcRelToScRel8( nRw2, nGrbitCol2, aCRD.Ref2, bRangeName );
++
++                if( IsComplColRange( nGrbitCol1, nGrbitCol2 ) )
++                    SetComplCol( aCRD );
++                else if( IsComplRowRange( nRw1, nRw2 ) )
++                    SetComplRow( aCRD );
++
++                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 (aExtInfo.mbExternal)
++                {
++                    aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
++                }
++                else
++                {
++                    if ( !ValidTab(nTabFirst) )
++                        rR1.SetTabDeleted( TRUE );
++                    if ( !ValidTab(nTabLast) )
++                        rR2.SetTabDeleted( TRUE );
++    
++                    aStack << aPool.Store( aCRD );
++                }
+ 			}
+ 				break;
+ 			default: bError = TRUE;
+@@ -1143,7 +1206,130 @@ ConvErr ExcelToSc8::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sa
+ 	return eRet;
+ }
+ 
++ConvErr ExcelToSc8::ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                       const String& rUrl, const vector<String>& rTabNames )
++{
++    String aFileUrl = ScGlobal::GetAbsDocName(rUrl, GetDocShell());
++
++    sal_uInt8               nOp, nByte;
++    bool                    bError = false;
++
++    SingleRefData           aSRD;
++    ComplRefData            aCRD;
++
++    if (eStatus != ConvOK)
++    {
++        rStrm.Ignore(nFormulaLen);
++        return eStatus;
++    }
++
++    if (nFormulaLen == 0)
++    {
++        aPool.Store(CREATE_STRING("-/-"));
++        aPool >> aStack;
++        rpArray = aPool[aStack.Get()];
++        return ConvOK;
++    }
++
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(aFileUrl);
++    sal_uInt16 nTabCount = rTabNames.size();
++
++    sal_Size nEndPos = rStrm.GetRecPos() + nFormulaLen;
++
++    while( (rStrm.GetRecPos() < nEndPos) && !bError )
++    {
++        rStrm >> nOp;
++
++        // #98524# always reset flags
++        aSRD.InitFlags();
++        aCRD.InitFlags();
++
++        switch( nOp )
++        {
++            case 0x1C: // Error Value
++            {
++                rStrm >> nByte;
++                DefTokenId eOc;
++                switch( nByte )
++                {
++                    case EXC_ERR_NULL:
++                    case EXC_ERR_DIV0:
++                    case EXC_ERR_VALUE:
++                    case EXC_ERR_REF:
++                    case EXC_ERR_NAME:
++                    case EXC_ERR_NUM:   eOc = ocStop;       break;
++                    case EXC_ERR_NA:    eOc = ocNotAvail;   break;
++                    default:            eOc = ocNoName;
++                }
++                aPool << eOc;
++                if( eOc != ocStop )
++                    aPool << ocOpen << ocClose;
++                aPool >> aStack;
++            }
++            break;
++            case 0x3A:
++            {
++                // cell reference in external range name
++                sal_uInt16 nExtTab1, nExtTab2, nRow, nGrbitCol;
++                rStrm >> nExtTab1 >> nExtTab2 >> nRow >> nGrbitCol;
++                if (nExtTab1 >= nTabCount || nExtTab2 >= nTabCount)
++                {
++                    bError = true;
++                    break;
++                }
++
++                aSRD.nTab = nExtTab1;
++                aSRD.SetFlag3D(true);
++                aSRD.SetTabRel(false);
++                ExcRelToScRel8(nRow, nGrbitCol, aSRD, true);
++                aCRD.Ref1 = aCRD.Ref2 = aSRD;
++                String aTabName = rTabNames[nExtTab1];
+ 
++                if (nExtTab1 == nExtTab2)
++                {
++                    // single cell reference
++                    aStack << aPool.StoreExtRef(nFileId, aTabName, aSRD);
++                }
++                else
++                {    
++                    // area reference
++                    aCRD.Ref2.nTab = nExtTab2;
++                    aStack << aPool.StoreExtRef(nFileId, aTabName, aCRD);
++                }
++            }
++            break;
++            default: 
++                bError = true;
++        }
++        bError |= !rStrm.IsValid();
++    }
++
++    ConvErr eRet;
++
++    if( bError )
++    {
++        aPool << ocBad;
++        aPool >> aStack;
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvErrNi;
++    }
++    else if( rStrm.GetRecPos() != nEndPos )
++    {
++        aPool << ocBad;
++        aPool >> aStack;
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvErrCount;
++    }
++    else
++    {
++        rpArray = aPool[ aStack.Get() ];
++        eRet = ConvOK;
++    }
++
++    rStrm.Seek(nEndPos);
++    return eRet;
++}
+ 
+ void ExcelToSc8::ExcRelToScRel8( UINT16 nRow, UINT16 nC, SingleRefData &rSRD, const BOOL bName )
+ {
+diff --git sc/source/filter/excel/read.cxx sc/source/filter/excel/read.cxx
+index 2cc592c..7f1c44b 100644
+--- sc/source/filter/excel/read.cxx
++++ sc/source/filter/excel/read.cxx
+@@ -967,7 +967,7 @@ FltError ImportExcel8::Read( void )
+                     case EXC_ID_SUPBOOK:        rLinkMgr.ReadSupbook( maStrm );     break;
+                     case EXC_ID_XCT:            rLinkMgr.ReadXct( maStrm );         break;
+                     case EXC_ID_CRN:            rLinkMgr.ReadCrn( maStrm );         break;
+-                    case EXC_ID_EXTERNNAME:     rLinkMgr.ReadExternname( maStrm );  break;
++                    case EXC_ID_EXTERNNAME:     rLinkMgr.ReadExternname( maStrm, pFormConv );  break;
+ 
+                     case EXC_ID_MSODRAWINGGROUP:rObjMgr.ReadMsoDrawingGroup( maStrm ); break;
+ 
+diff --git sc/source/filter/excel/tokstack.cxx sc/source/filter/excel/tokstack.cxx
+index 20ada63..9c4ddba 100644
+--- sc/source/filter/excel/tokstack.cxx
++++ sc/source/filter/excel/tokstack.cxx
+@@ -395,6 +395,34 @@ void TokenPool::GetElement( const UINT16 nId )
+                         pScToken->AddMatrix( p );
+                 }
+                 break;
++            case T_ExtName:
++            {
++                UINT16 n = pElement[nId];
++                if (n < maExtNames.size())
++                {
++                    const ExtName& r = maExtNames[n];
++                    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 +505,34 @@ void TokenPool::GetElementRek( const UINT16 nId )
+                             pScToken->AddMatrix( p );
+                     }
+                     break;
++                case T_ExtName:
++                {
++                    UINT16 n = pElement[*pAkt];
++                    if (n < maExtNames.size())
++                    {
++                        const ExtName& r = maExtNames[n];
++                        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 +780,68 @@ const TokenId TokenPool::StoreMatrix( SCSIZE nC, SCSIZE nR )
+     return ( const TokenId ) nElementAkt;
+ }
+ 
++const TokenId TokenPool::StoreExtName( sal_uInt16 nFileId, const String& rName )
++{
++    if ( nElementAkt >= nElement )
++        GrowElement();
++
++    pElement[nElementAkt] = static_cast<UINT16>(maExtNames.size());
++    pType[nElementAkt] = T_ExtName;
++    
++    maExtNames.push_back(ExtName());
++    ExtName& r = maExtNames.back();
++    r.mnFileId = nFileId;
++    r.maName = rName;
++
++    ++nElementAkt;
++
++    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..947b4ce 100644
+--- sc/source/filter/excel/xeformula.cxx
++++ sc/source/filter/excel/xeformula.cxx
+@@ -42,6 +42,11 @@
+ #include "xelink.hxx"
+ #include "xename.hxx"
+ 
++#include "document.hxx"
++#include "externalrefmgr.hxx"
++
++#include <memory>
++
+ // External reference log =====================================================
+ 
+ XclExpRefLogEntry::XclExpRefLogEntry() :
+@@ -225,6 +230,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 +330,7 @@ private:
+     void                ProcessBoolean( const XclExpTokenData& rTokData );
+     void                ProcessDdeLink( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+     void                ProcessExternal( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
++    void                ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+ 
+     void                ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+     void                PrepareFunction( XclExpFuncData& rFuncData );
+@@ -1114,6 +1146,12 @@ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8
+     StackVar eTokType = aTokData.GetType();
+     OpCode eOpCode = aTokData.GetOpCode();
+ 
++    if (eOpCode == ocExternalName)
++    {
++        ProcessExternalName( aTokData, nExpClass );
++        return GetNextToken();
++    }
++
+     switch( eTokType )
+     {
+         case svUnknown:     mbOk = false;                           break;
+@@ -1248,6 +1286,131 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
+         ProcessFunction( rTokData, nExpClass );
+ }
+ 
++void XclExpFmlaCompImpl::ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
++{
++    StackVar eType = rTokData.GetType();
++
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    USHORT nFileId = rTokData.mpScToken->GetIndex();
++    switch (eType)
++    {
++        case svSingleRef:
++        {
++            if (!mpScBasePos)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++            SingleRefData aRef(rTokData.mpScToken->GetSingleRef());
++            aRef.CalcAbsIfRel(*mpScBasePos);
++            const String& rTabName = rTokData.mpScToken->GetString();
++            ScToken* p = pRefMgr->getSingleRefToken(nFileId, rTabName, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab), NULL, NULL);
++            if (!p)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++
++            mpLinkMgr->StoreCell(nFileId, rTabName, aRef);
++
++            XclAddress aXclPos(ScAddress::UNINITIALIZED);
++            ConvertRefData(aRef, aXclPos, false, false, false);
++
++            sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
++            mpLinkMgr->FindExtSheet(nFileId, rTabName, 1, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry());
++            sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_REFERR3D : EXC_TOKID_REF3D;
++            AppendOpTokenId(GetTokenId(nBaseId, EXC_TOKCLASS_REF), nExpClass, rTokData.mnSpaces);
++            Append(nExtSheet);
++            if (meBiff <= EXC_BIFF5)
++            {
++                Append(0, 8);
++                Append(static_cast<sal_uInt16>(nFirstSBTab));
++                Append(static_cast<sal_uInt16>(nFirstSBTab));
++            }
++            AppendAddress(aXclPos);
++        }
++        break;
++        case svDoubleRef:
++        {
++            if (!mpScBasePos)
++            {
++                AppendErrorToken(XclTools::GetXclErrorCode(errNoRef), rTokData.mnSpaces);
++                break;
++            }
++            ComplRefData aRef(rTokData.mpScToken->GetDoubleRef());
++            aRef.CalcAbsIfRel(*mpScBasePos);
++            const String& rTabName = rTokData.mpScToken->GetString();
++            const SingleRefData& r1 = aRef.Ref1;
++            const SingleRefData& r2 = aRef.Ref2;
++            ScRange aRange(r1.nCol, r1.nRow, r1.nTab, r2.nCol, r2.nRow, r2.nTab);
++            ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, aRange, NULL);
++            if (!pArray)
++            {
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++                break;
++            }
++
++            mpLinkMgr->StoreCellRange(nFileId, rTabName, aRef);
++            XclRange aXclRange(ScAddress::UNINITIALIZED);
++            ConvertRefData(aRef, aXclRange, false);
++            sal_uInt16 nExtSheet, nFirstSBTab, nLastSBTab;
++            sal_uInt16 nTabSpan = r2.nTab - r1.nTab + 1;
++            mpLinkMgr->FindExtSheet(nFileId, rTabName, nTabSpan, nExtSheet, nFirstSBTab, nLastSBTab, GetNewRefLogEntry());
++
++            sal_uInt8 nBaseId = lclIsRefDel2D(aRef) ? EXC_TOKID_AREAERR3D : EXC_TOKID_AREA3D;
++            AppendOpTokenId(GetTokenId( nBaseId, EXC_TOKCLASS_REF ), nExpClass, rTokData.mnSpaces);
++            Append(nExtSheet);
++            if (meBiff <= EXC_BIFF5)
++            {
++                Append(0, 8);
++                Append(static_cast<sal_uInt16>(nFirstSBTab));
++                Append(static_cast<sal_uInt16>(nLastSBTab));
++            }
++            AppendRange(aXclRange);
++        }
++        break;
++        case svExternalName:
++        {
++            const String& aName = rTokData.mpScToken->GetString();
++            ScTokenArray* pArray = pRefMgr->getRangeNameTokens(nFileId, aName);
++            if (!pArray || !mpScBasePos)
++            {    
++                AppendErrorToken(XclTools::GetXclErrorCode(errNoName), rTokData.mnSpaces);
++                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)
++                {
++                    if (p->GetType() == svSingleRef)
++                    {
++                        SingleRefData aData(p->GetSingleRef());
++                        aData.CalcAbsIfRel(*mpScBasePos);
++                        mpLinkMgr->StoreCell(nFileId, p->GetString(), aData);
++                    }
++                    else if (p->GetType() == svDoubleRef)
++                    {
++                        ComplRefData aData(p->GetDoubleRef());
++                        aData.CalcAbsIfRel(*mpScBasePos);
++                        mpLinkMgr->StoreCellRange(nFileId, p->GetString(), aData);
++                    }
++                }
++            }
++
++            const String* pFile = pRefMgr->getExternalFileName(nFileId);
++            sal_uInt16 nExtSheet, nExtName;
++            if (mpLinkMgr->InsertExtName(nExtSheet, nExtName, *pFile, aName, pArray))
++                AppendNameXToken(nExtSheet, nExtName, nExpClass, rTokData.mnSpaces);
++            else
++                AppendErrorToken(EXC_ERR_REF, rTokData.mnSpaces);
++        }
++        break;
++    }
++}
++
+ void XclExpFmlaCompImpl::ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
+ {
+     OpCode eOpCode = rTokData.GetOpCode();
+@@ -1623,32 +1786,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..08517ca 100644
+--- sc/source/filter/excel/xelink.cxx
++++ sc/source/filter/excel/xelink.cxx
+@@ -38,6 +38,14 @@
+ #include "document.hxx"
+ #include "cell.hxx"
+ #include "scextopt.hxx"
++#include "externalrefmgr.hxx"
++
++#include <vector>
++#include <memory>
++
++using ::std::auto_ptr;
++using ::std::find_if;
++using ::std::vector;
+ 
+ // ============================================================================
+ // *** Helper classes ***
+@@ -102,6 +110,25 @@ private:
+     XclExpCachedMatRef  mxMatrix;       /// Cached results of the DDE link.
+ };
+ 
++// ----------------------------------------------------------------------------
++
++class XclExpSupbook;
++
++class XclExpExtName : public XclExpExtNameBase
++{
++public:
++    explicit            XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const String& rName,
++                                       const ScTokenArray* pArray );
++
++private:
++    /** Writes additional record contents. */
++    virtual void        WriteAddData( XclExpStream& rStrm );
++
++private:
++    const XclExpSupbook&    mrSupbook;
++    auto_ptr<ScTokenArray>  mpArray;
++};
++
+ // List of external names =====================================================
+ 
+ /** List of all external names of a sheet. */
+@@ -117,6 +144,8 @@ public:
+         @return  The 1-based (Excel-like) list index of the DDE link. */
+     sal_uInt16          InsertDde( const String& rApplic, const String& rTopic, const String& rItem );
+ 
++    sal_uInt16          InsertExtName( const XclExpSupbook& rSupbook, const String& rName, const ScTokenArray* pArray );
++
+     /** Writes the EXTERNNAME record list. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
+@@ -220,6 +249,9 @@ public:
+     /** Stores all cells in the given range in the CRN list. */
+     void                StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange );
+ 
++    void                StoreCell( const XclExpRoot& rRoot, const ScAddress& rCell, const ScToken& rToken );
++    void                StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange, const ScToken& rToken );
++
+     /** Writes the XCT and all CRN records. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
+@@ -319,6 +351,12 @@ public:
+     /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
+     void                StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab );
+ 
++    void                StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken );
++    void                StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken );
++
++    sal_uInt16          GetTabIndex( const String& rTabName ) const;
++    sal_uInt16          GetTabCount() const;
++
+     /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
+     sal_uInt16          InsertTabName( const String& rTabName );
+     /** Finds or inserts an EXTERNNAME record for add-ins.
+@@ -328,6 +366,8 @@ public:
+         @return  The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+     sal_uInt16          InsertDde( const String& rItem );
+ 
++    sal_uInt16          InsertExtName( const String& rName, const ScTokenArray* pArray );
++
+     /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
+@@ -394,6 +434,9 @@ public:
+     /** Stores all cells in the given range in a CRN record list. */
+     void                StoreCellRange( 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 +450,25 @@ public:
+                             sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+                             const String& rApplic, const String& rTopic, const String& rItem );
+ 
++    bool                InsertExtName(
++                            sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
++                            const String& rName, const ScTokenArray* pArray );
++
++    XclExpXti           GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                XclExpRefLogEntry* pRefLogEntry = NULL );
++
+     /** Writes all SUPBOOK records with their sub records. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
++    struct XclExpSBIndex
++    {
++        sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
++        sal_uInt16          mnSBTab;            /// Sheet name index in SUPBOOK for an Excel sheet.
++        inline void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
++                                { mnSupbook = nSupbook; mnSBTab = nSBTab; }
++    };
++    typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
++
+ private:
+     typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
+     typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
+@@ -431,19 +490,8 @@ private:
+     /** Appends a new SUPBOOK to the list.
+         @return  The list index of the SUPBOOK record. */
+     sal_uInt16          Append( XclExpSupbookRef xSupbook );
+-    /** Creates and appends an external SUPBOOK record from the Calc sheet nScTab. */
+-    void                AddExtSupbook( SCTAB nScTab );
+ 
+ private:
+-    struct XclExpSBIndex
+-    {
+-        sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
+-        sal_uInt16          mnSBTab;            /// Sheet name in SUPBOOK for an Excel sheet.
+-        inline void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
+-                                { mnSupbook = nSupbook; mnSBTab = nSBTab; }
+-    };
+-    typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
+-
+     XclExpSupbookList   maSupbookList;      /// List of all SUPBOOK records.
+     XclExpSBIndexVec    maSBIndexVec;       /// SUPBOOK and sheet name index for each Excel sheet.
+     sal_uInt16          mnOwnDocSB;         /// Index to SUPBOOK for own document.
+@@ -464,9 +512,16 @@ public:
+     /** Derived classes search for a special EXTERNSHEET index for the own document. */
+     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode ) = 0;
+ 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++                               XclExpRefLogEntry* pRefLogEntry ) = 0;
++
+     /** Derived classes store all cells in the given range in a CRN record list. */
+     virtual void        StoreCellRange( 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 +531,10 @@ public:
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rApplic, const String& rTopic, const String& rItem ) = 0;
+ 
++    virtual bool        InsertExtName(
++                            sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
++                            const String& rName, const ScTokenArray* pArray ) = 0;
++
+     /** Derived classes write the entire link table to the passed stream. */
+     virtual void        Save( XclExpStream& rStrm ) = 0;
+ 
+@@ -497,15 +556,27 @@ public:
+                             XclExpRefLogEntry* pRefLogEntry );
+     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
+ 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++                               XclExpRefLogEntry* pRefLogEntry );
++
+     virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
+ 
++    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,
+                             const String& rName );
++
+     virtual bool        InsertDde(
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rApplic, const String& rTopic, const String& rItem );
+ 
++    virtual bool        InsertExtName(
++                            sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
++                            const String& rName, const ScTokenArray* pArray );
++
+     virtual void        Save( XclExpStream& rStrm );
+ 
+ private:
+@@ -550,15 +621,27 @@ public:
+                             XclExpRefLogEntry* pRefLogEntry );
+     virtual sal_uInt16  FindExtSheet( sal_Unicode cCode );
+ 
++    virtual void FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                               sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++                               XclExpRefLogEntry* pRefLogEntry );
++
+     virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
+ 
++    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,
+                             const String& rName );
++
+     virtual bool        InsertDde(
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rApplic, const String& rTopic, const String& rItem );
+ 
++    virtual bool        InsertExtName(
++                            sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
++                            const String& rName, const ScTokenArray* pArray );
++
+     virtual void        Save( XclExpStream& rStrm );
+ 
+ private:
+@@ -885,6 +968,100 @@ void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
+         mxMatrix->Save( rStrm );
+ }
+ 
++// ----------------------------------------------------------------------------
++
++XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook, const String& rName, const ScTokenArray* pArray ) :
++    XclExpExtNameBase( rRoot, rName ),
++    mrSupbook(rSupbook),
++    mpArray(pArray->Clone())
++{
++}
++
++void XclExpExtName::WriteAddData( XclExpStream& rStrm )
++{
++    // Write only if it only has a single token that is either a cell or cell 
++    // range address.  Excel just writes '02 00 1C 17' for all the other types
++    // of external names.
++
++    do
++    {
++        if (mpArray->GetLen() != 1)
++            break;
++
++        const ScToken* p = mpArray->First();
++        if (p->GetOpCode() != ocExternalName)
++            break;
++
++        switch (p->GetType())
++        {
++            case svSingleRef:
++            {
++                const SingleRefData& rRef = p->GetSingleRef();
++                if (rRef.IsTabRel())
++                    break;
++
++                bool bColRel = rRef.IsColRel();
++                bool bRowRel = rRef.IsRowRel();
++                sal_uInt16 nCol = bColRel ? rRef.nRelCol : rRef.nCol;
++                sal_uInt16 nRow = bRowRel ? rRef.nRelRow : rRef.nRow;
++                if (bColRel) nCol |= 0x4000;
++                if (bRowRel) nCol |= 0x8000;
++
++                const String& rTabName = p->GetString();
++                sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
++
++                // size is always 9
++                rStrm << static_cast<sal_uInt16>(9);
++                // operator token (3A for cell reference)
++                rStrm << static_cast<sal_uInt8>(0x3A);
++                // cell address (Excel's address has 2 sheet IDs.)
++                rStrm << nSBTab << nSBTab << nRow << nCol;
++                return;
++            }
++            case svDoubleRef:
++            {
++                const ComplRefData& rRef = p->GetDoubleRef();
++                const SingleRefData& r1 = rRef.Ref1;
++                const SingleRefData& r2 = rRef.Ref2;
++                if (r1.IsTabRel() || r2.IsTabRel())
++                    break;
++
++                sal_uInt16 nTab1 = r1.nTab;
++                sal_uInt16 nTab2 = r2.nTab;
++                bool bCol1Rel = r1.IsColRel();
++                bool bRow1Rel = r1.IsRowRel();
++                bool bCol2Rel = r2.IsColRel();
++                bool bRow2Rel = r2.IsRowRel();
++
++                sal_uInt16 nCol1 = bCol1Rel ? r1.nRelCol : r1.nCol;
++                sal_uInt16 nCol2 = bCol2Rel ? r2.nRelCol : r2.nCol;
++                sal_uInt16 nRow1 = bRow1Rel ? r1.nRelRow : r1.nRow;
++                sal_uInt16 nRow2 = bRow2Rel ? r2.nRelRow : r2.nRow;
++                if (bCol1Rel) nCol1 |= 0x4000;
++                if (bRow1Rel) nCol1 |= 0x8000;
++                if (bCol2Rel) nCol2 |= 0x4000;
++                if (bRow2Rel) nCol2 |= 0x8000;
++
++                const String& rTabName = p->GetString();
++                sal_uInt16 nSBTab = mrSupbook.GetTabIndex(rTabName);
++
++                // size is always 13 (0x0D)
++                rStrm << static_cast<sal_uInt16>(13);
++                // operator token (3B for area reference)
++                rStrm << static_cast<sal_uInt8>(0x3B);
++                // range (area) address
++                sal_uInt16 nSBTab2 = nSBTab + nTab2 - nTab1; 
++                rStrm << nSBTab << nSBTab2 << nRow1 << nRow2 << nCol1 << nCol2;
++                return;
++            }
++        }
++    }
++    while (false);
++
++    // special value for #REF! (02 00 1C 17)
++    rStrm << static_cast<sal_uInt16>(2) << EXC_TOKID_ERR << EXC_ERR_REF;
++}
++
+ // List of external names =====================================================
+ 
+ XclExpExtNameBuffer::XclExpExtNameBuffer( const XclExpRoot& rRoot ) :
+@@ -920,6 +1097,12 @@ sal_uInt16 XclExpExtNameBuffer::InsertDde(
+     return nIndex;
+ }
+ 
++sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook, const String& rName, const ScTokenArray* pArray )
++{
++    sal_uInt16 nIndex = GetIndex( rName );
++    return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, pArray ) );
++}
++
+ void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
+ {
+     maNameList.Save( rStrm );
+@@ -1066,6 +1249,78 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
+     maUsedCells.SetMultiMarkArea( rRange );
+ }
+ 
++void XclExpXct::StoreCell( const XclExpRoot& /*rRoot*/, const ScAddress& rCell, const ScToken& rToken )
++{
++    switch (rToken.GetType())
++    {
++        case svString:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnString(rCell.Col(), rCell.Row(), rToken.GetString()));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++        case svDouble:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnDouble(rCell.Col(), rCell.Row(), rToken.GetDouble()));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++        case svEmptyCell:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnDouble(rCell.Col(), rCell.Row(), 0.0));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++    }
++}
++
++void XclExpXct::StoreCellRange( const XclExpRoot& /*rRoot*/, const ScRange& rRange, const ScToken& rToken )
++{
++    if (rToken.GetType() != svMatrix)
++        return;
++
++    if (rRange.aStart.Tab() != rRange.aEnd.Tab())
++        // multi-table range is not supported here.
++        return;
++
++    const ScMatrix* pMtx = rToken.GetMatrix();
++    if (!pMtx)
++        return;
++
++    SCSIZE nCols, nRows;
++    pMtx->GetDimensions(nCols, nRows);
++    const ScAddress& s = rRange.aStart;
++    const ScAddress& e = rRange.aEnd;
++    if (static_cast<SCCOL>(nCols) != e.Col() - s.Col() + 1 || 
++        static_cast<SCROW>(nRows) != e.Row() - s.Row() + 1)
++    {
++        // size mis-match!
++        return;
++    }
++
++    for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
++    {
++        for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
++        {
++            if (pMtx->IsString(nCol, nRow))
++            {
++                XclExpCrnRef xCrn(new XclExpCrnString(
++                    s.Col() + nCol, s.Row() + nRow, pMtx->GetString(nCol, nRow)));
++                maCrnList.AppendRecord(xCrn);
++            }
++            else if (pMtx->IsValueOrEmpty(nCol, nRow))
++            {
++                XclExpCrnRef xCrn(new XclExpCrnDouble(
++                    s.Col() + nCol, s.Row() + nRow, pMtx->GetDouble(nCol, nRow)));
++                maCrnList.AppendRecord(xCrn);
++            }
++        }
++    }
++}
++
+ void XclExpXct::Save( XclExpStream& rStrm )
+ {
+     XclExpRecord::Save( rStrm );
+@@ -1168,6 +1423,17 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) :
+     mnXclTabCount( 0 )
+ {
+     SetRecSize( 2 + maUrlEncoded.GetSize() );
++
++    // We need to create all tables up front to ensure the correct table order.
++    ScExternalRefManager* pRefMgr = rRoot.GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
++    const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++    if (!pTabNames)
++        return;
++
++    vector<String>::const_iterator itr = pTabNames->begin(), itrEnd = pTabNames->end();
++    for (; itr != itrEnd; ++itr)
++        InsertTabName(*itr);
+ }
+ 
+ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) :
+@@ -1206,6 +1472,46 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+         xXct->StoreCellRange( GetRoot(), rRange );
+ }
+ 
++void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken )
++{
++    XclExpXctRef xXct = maXctList.GetRecord(nSBTab);
++    if (!xXct.is())
++        return;
++
++    xXct->StoreCell(GetRoot(), rCell, rToken);
++}
++
++void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken )
++{
++    if (rRange.aStart.Tab() != rRange.aEnd.Tab())
++        // multi-table range is not allowed!
++        return;
++
++    XclExpXctRef xXct = maXctList.GetRecord(nSBTab);
++    if (!xXct.is())
++        return;
++
++    xXct->StoreCellRange(GetRoot(), rRange, rToken);
++}
++
++sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName ) const
++{
++    XclExpString aXclName(rTabName);
++    size_t nSize = maXctList.GetSize();
++    for (size_t i = 0; i < nSize; ++i)
++    {
++        XclExpXctRef aRec = maXctList.GetRecord(i);
++        if (aXclName == aRec->GetTabName())
++            return ulimit_cast<sal_uInt16>(i);
++    }
++    return EXC_NOTAB;
++}
++
++sal_uInt16 XclExpSupbook::GetTabCount() const
++{
++    return ulimit_cast<sal_uInt16>(maXctList.GetSize());
++}
++
+ sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName )
+ {
+     DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
+@@ -1226,6 +1532,11 @@ sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
+     return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
+ }
+ 
++sal_uInt16 XclExpSupbook::InsertExtName( const String& rName, const ScTokenArray* pArray )
++{
++    return GetExtNameBuffer().InsertExtName(*this, rName, pArray);
++}
++
+ void XclExpSupbook::Save( XclExpStream& rStrm )
+ {
+     // SUPBOOK record
+@@ -1289,11 +1600,6 @@ XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+         mnOwnDocSB = Append( xSupbook );
+         for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
+             maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
+-
+-        // add SUPBOOKs with external references
+-        for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
+-            if( rTabInfo.IsExternalTab( nScTab ) )
+-                AddExtSupbook( nScTab );
+     }
+ }
+ 
+@@ -1352,6 +1658,130 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+     }
+ }
+ 
++namespace {
++
++class FindSBIndexEntry
++{
++public:
++    explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) :
++        mnSupbookId(nSupbookId), mnTabId(nTabId) {}
++
++    bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const
++    {
++        return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab;
++    }
++
++private:
++    sal_uInt16 mnSupbookId;
++    sal_uInt16 mnTabId;
++};
++
++}
++
++void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell )
++{
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++    if (!pUrl)
++        return;
++
++    XclExpSupbookRef xSupbook;
++    sal_uInt16 nSupbookId;
++    if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
++    {
++        xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
++        nSupbookId = Append(xSupbook);
++    }
++
++    ScToken* pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL);
++    if (!pToken)
++        return;
++
++    sal_uInt16 nSheetId = xSupbook->GetTabIndex(rTabName);
++    if (nSheetId == EXC_NOTAB)
++        // specified table name not found in this SUPBOOK.
++        return;
++
++    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;
++    }
++
++    xSupbook->StoreCell(nSheetId, rCell, *pToken);
++}
++
++void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange )
++{
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++    if (!pUrl)
++        return;
++
++    XclExpSupbookRef xSupbook;
++    sal_uInt16 nSupbookId;
++    if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
++    {
++        xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
++        nSupbookId = Append(xSupbook);
++    }
++
++    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(nTabCount);
++
++    // This is a new'ed instance, so we must manage its life cycle here.
++    ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
++    if (!pArray)
++        return;
++
++    for (ScToken* p = pArray->First(); p; p = pArray->Next())
++    {
++        if (p->GetType() == svMatrix)
++            aMatrixList.push_back(p);
++        else if (p->GetOpCode() != ocSep)
++        {
++            // This is supposed to be ocSep!!!
++            return;
++        }
++    }
++
++    if (aMatrixList.size() != static_cast<size_t>(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 = 0; nTab < nTabCount; ++nTab)
++    {
++        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);
++        if (itr == itrEnd)
++        {
++            maSBIndexVec.push_back(XclExpSBIndex());
++            XclExpSBIndex& r = maSBIndexVec.back();
++            r.mnSupbook = nSupbookId;
++            r.mnSBTab   = nSheetId;
++        }
++
++        xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab]);
++    }
++}
++
+ bool XclExpSupbookBuffer::InsertAddIn(
+         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1383,6 +1813,78 @@ bool XclExpSupbookBuffer::InsertDde(
+     return rnExtName > 0;
+ }
+ 
++bool XclExpSupbookBuffer::InsertExtName(
++        sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
++        const String& rName, const ScTokenArray* pArray )
++{
++    XclExpSupbookRef xSupbook;
++    if (!GetSupbookUrl(xSupbook, rnSupbook, rUrl))
++    {
++        xSupbook.reset( new XclExpSupbook(GetRoot(), rUrl) );
++        rnSupbook = Append(xSupbook);
++    }
++    rnExtName = xSupbook->InsertExtName(rName, pArray);
++    return rnExtName > 0;
++}
++
++XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                       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;
++
++    sal_uInt16 nFirstSheetId = xSupbook->GetTabIndex(rTabName);
++    if (nFirstSheetId == EXC_NOTAB)
++    {
++        // first sheet not found in SUPBOOK.
++        return aXti;
++    }
++    sal_uInt16 nSheetCount = xSupbook->GetTabCount();
++    for (sal_uInt16 i = 0; i < nXclTabSpan; ++i)
++    {
++        sal_uInt16 nSheetId = nFirstSheetId + i;
++        if (nSheetId >= nSheetCount)
++            return aXti;
++
++        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 (i == 0)
++            aXti.mnFirstSBTab = nSheetId;
++        if (i == nXclTabSpan - 1)
++            aXti.mnLastSBTab = nSheetId;
++    }
++
++    if (pRefLogEntry)
++    {
++        pRefLogEntry->mnFirstXclTab = 0;
++        pRefLogEntry->mnLastXclTab  = 0;
++        if (xSupbook.is())
++            xSupbook->FillRefLogEntry(*pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab);
++    }
++
++    return aXti;
++}
++
+ void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
+ {
+     maSupbookList.Save( rStrm );
+@@ -1424,27 +1926,6 @@ sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
+     return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
+ }
+ 
+-void XclExpSupbookBuffer::AddExtSupbook( SCTAB nScTab )
+-{
+-    sal_uInt16 nXclTab = GetTabInfo().GetXclTab( nScTab );
+-    DBG_ASSERT( nXclTab < maSBIndexVec.size(), "XclExpSupbookBuffer::AddExtSupbook - out of range" );
+-
+-    // find ext doc name or append new one, save position in maSBIndexBuffer
+-    const String& rUrl = GetDoc().GetLinkDoc( nScTab );
+-    DBG_ASSERT( rUrl.Len(), "XclExpSupbookBuffer::AddExtSupbook - missing external linked sheet" );
+-    sal_uInt16 nSupbook;
+-    XclExpSupbookRef xSupbook;
+-    if( !GetSupbookUrl( xSupbook, nSupbook, rUrl ) )
+-    {
+-        xSupbook.reset( new XclExpSupbook( GetRoot(), rUrl ) );
+-        nSupbook = Append( xSupbook );
+-    }
+-
+-    // append new sheet name, save SUPBOOK and sheet position in maSBIndexVec
+-    maSBIndexVec[ nXclTab ].mnSupbook = nSupbook;
+-    maSBIndexVec[ nXclTab ].mnSBTab = xSupbook->InsertTabName( GetDoc().GetLinkTab( nScTab ) );
+-}
+-
+ // Export link manager ========================================================
+ 
+ XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
+@@ -1485,11 +1966,29 @@ sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
+     return nExtSheet;
+ }
+ 
++void XclExpLinkManagerImpl5::FindExtSheet( 
++    sal_uInt16 /*nFileId*/, const String& /*rTabName*/, sal_uInt16 /*nXclTabSpan*/, 
++    sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnFirstSBTab*/, sal_uInt16& /*rnLastSBTab*/, 
++    XclExpRefLogEntry* /*pRefLogEntry*/ )
++{
++    // not implemented
++}
++
+ void XclExpLinkManagerImpl5::StoreCellRange( const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
+ {
+     // not implemented
+ }
+ 
++void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef*/ )
++{
++    // not implemented
++}
++
++void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
++{
++    // not implemented
++}
++
+ bool XclExpLinkManagerImpl5::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1510,6 +2009,14 @@ bool XclExpLinkManagerImpl5::InsertDde(
+     return false;
+ }
+ 
++bool XclExpLinkManagerImpl5::InsertExtName(
++        sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rUrl*/,
++        const String& /*rName*/, const ScTokenArray* /*pArray*/ )
++{
++    // not implemented
++    return false;
++}
++
+ void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
+ {
+     if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
+@@ -1630,6 +2137,17 @@ sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
+     return InsertXti( maSBBuffer.GetXti( EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ }
+ 
++void XclExpLinkManagerImpl8::FindExtSheet( 
++    sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan, 
++    sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++    XclExpRefLogEntry* pRefLogEntry )
++{
++    XclExpXti aXti = maSBBuffer.GetXti(nFileId, rTabName, nXclTabSpan, 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 +2170,19 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
+     }
+ }
+ 
++void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
++{
++    ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
++    maSBBuffer.StoreCell(nFileId, rTabName, aAddr);
++}
++
++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, rTabName, aRange);
++}
++
+ bool XclExpLinkManagerImpl8::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1677,6 +2208,18 @@ bool XclExpLinkManagerImpl8::InsertDde(
+     return false;
+ }
+ 
++bool XclExpLinkManagerImpl8::InsertExtName(
++    sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl, const ScTokenArray* pArray )
++{
++    sal_uInt16 nSupbook;
++    if( maSBBuffer.InsertExtName( nSupbook, rnExtName, rUrl, rName, pArray ) )
++    {
++        rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
++        return true;
++    }
++    return false;
++}
++
+ void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
+ {
+     if( !maXtiVec.empty() )
+@@ -1745,6 +2288,13 @@ sal_uInt16 XclExpLinkManager::FindExtSheet( sal_Unicode cCode )
+     return mxImpl->FindExtSheet( cCode );
+ }
+ 
++void XclExpLinkManager::FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                      sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab,
++                                      XclExpRefLogEntry* pRefLogEntry )
++{
++    mxImpl->FindExtSheet( nFileId, rTabName, nXclTabSpan, rnExtSheet, rnFirstSBTab, rnLastSBTab, pRefLogEntry );
++}
++
+ void XclExpLinkManager::StoreCell( const SingleRefData& rRef )
+ {
+     mxImpl->StoreCellRange( rRef, rRef );
+@@ -1755,6 +2305,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
+     mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
+ }
+ 
++void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef )
++{
++    mxImpl->StoreCell( nFileId, rTabName, rRef );
++}
++
++void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef )
++{
++    mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 );
++}
++
+ bool XclExpLinkManager::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1768,6 +2328,13 @@ bool XclExpLinkManager::InsertDde(
+     return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
+ }
+ 
++bool XclExpLinkManager::InsertExtName(
++    sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl,
++    const ScTokenArray* pArray )
++{
++    return mxImpl->InsertExtName( rnExtSheet, rnExtName, rUrl, rName, pArray );
++}
++
+ void XclExpLinkManager::Save( XclExpStream& rStrm )
+ {
+     mxImpl->Save( rStrm );
+diff --git sc/source/filter/excel/xilink.cxx sc/source/filter/excel/xilink.cxx
+index 01932a5..ab4c08b 100644
+--- sc/source/filter/excel/xilink.cxx
++++ sc/source/filter/excel/xilink.cxx
+@@ -38,6 +38,13 @@
+ #include "xistream.hxx"
+ #include "xihelper.hxx"
+ #include "xiname.hxx"
++#include "excform.hxx"
++#include "tokenarray.hxx"
++#include "externalrefmgr.hxx"
++
++#include <vector>
++
++using ::std::vector;
+ 
+ // ============================================================================
+ // *** Helper classes ***
+@@ -52,8 +59,7 @@ public:
+     /** Reads a cached value and stores it with its cell address. */
+     explicit            XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+ 
+-    /** Copies the cached value to sheet nTab in the document. */
+-    void                SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const;
++    const XclAddress&   GetAddress() const;
+ 
+ private:
+     XclAddress          maXclPos;       /// Excel position of the cached cell.
+@@ -71,16 +77,11 @@ public:
+                         ~XclImpSupbookTab();
+ 
+     inline const String& GetTabName() const { return maTabName; }
+-    inline SCTAB        GetScTab() const { return mnScTab; }
+ 
+     /** Reads a CRN record (external referenced cell) at the specified address. */
+     void                ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos );
+ 
+-    /** 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 );
++    void                LoadCachedValues(ScExternalRefCache::Table* pCacheTable);
+ 
+ private:
+     typedef ScfDelList< XclImpCrn > XclImpCrnList;
+@@ -105,7 +106,7 @@ public:
+     /** Reads a CRN record (external referenced cell). */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns the SUPBOOK record type. */
+     inline XclSupbookType GetType() const { return meType; }
+@@ -113,11 +114,6 @@ public:
+     /** Returns the URL of the external document. */
+     inline const String& GetXclUrl() const { return maXclUrl; }
+ 
+-    /** 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;
+-
+     /** Returns the external name specified by an index from the Excel document (one-based). */
+     const XclImpExtName* GetExternName( sal_uInt16 nXclIndex ) const;
+     /** Tries to decode the URL to OLE or DDE link components.
+@@ -128,10 +124,11 @@ public:
+     /** Returns the specified macro name (1-based) or an empty string on error. */
+     const String&       GetMacroName( sal_uInt16 nXclNameIdx ) const;
+ 
+-    /** 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 );
++    const String&       GetTabName( sal_uInt16 nXtiTab ) const;
++
++    sal_uInt16          GetTabCount() const;
++
++    void                LoadCachedValues();
+ 
+ private:
+     typedef ScfDelList< XclImpSupbookTab >  XclImpSupbookTabList;
+@@ -180,7 +177,7 @@ public:
+     /** Reads a CRN record and appends it to the current SUPBOOK. */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns true, if the specified XTI entry contains an internal reference. */
+     bool                IsSelfRef( sal_uInt16 nXtiIndex ) const;
+@@ -191,6 +188,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;
++
++    /** Returns the absolute file URL of a supporting workbook specified by
++        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.
+@@ -199,18 +203,13 @@ public:
+     /** Returns the specified macro name or an empty string on error. */
+     const String&       GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
+ 
+-    /** 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;
+-
+ 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;
+ 
+-    /** Creates all external sheets in the Calc document. */
+-    void                CreateTables();
++    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.
+@@ -291,14 +290,13 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa
+ 
+ // External names =============================================================
+ 
+-XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn )
++XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn, ExcelToSc* pFormulaConv )
+ {
+     sal_uInt16 nFlags;
+     sal_uInt8 nLen;
+ 
+     rStrm >> nFlags >> mnStorageId >> nLen ;
+     maName = rStrm.ReadUniString( nLen );
+-
+     if( ::get_flag( nFlags, EXC_EXTN_BUILTIN ) || !::get_flag( nFlags, EXC_EXTN_OLE_OR_DDE ) )
+     {
+         if( bAddIn )
+@@ -319,6 +317,28 @@ XclImpExtName::XclImpExtName( XclImpStream& rStrm, bool bAddIn )
+ 
+     if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) )
+         mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) );
++
++    if (meType == xlExtName)
++    {
++        if (mnStorageId == 0)
++        {
++            if (pFormulaConv)
++            {
++                const ScTokenArray* pArray = NULL;
++                sal_uInt16 nFmlaLen;
++                rStrm >> nFmlaLen;
++                vector<String> aTabNames;
++                sal_uInt16 nCount = rSupbook.GetTabCount();
++                aTabNames.reserve(nCount);
++                for (sal_uInt16 i = 0; i < nCount; ++i)
++                    aTabNames.push_back(rSupbook.GetTabName(i));
++
++                pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
++                if (pArray)
++                    mxArray.reset(pArray->Clone());
++            }
++        }
++    }
+ }
+ 
+ XclImpExtName::~XclImpExtName()
+@@ -333,6 +353,12 @@ void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, cons
+     rDoc.CreateDdeLink( rApplic, rTopic, maName, SC_DDE_DEFAULT, xResults );
+ }
+ 
++void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const
++{
++    ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
++    pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
++}
++
+ // Cached external cells ======================================================
+ 
+ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
+@@ -341,29 +367,9 @@ XclImpCrn::XclImpCrn( XclImpStream& rStrm, const XclAddress& rXclPos ) :
+ {
+ }
+ 
+-void XclImpCrn::SetCell( const XclImpRoot& rRoot, SCTAB nScTab ) const
++const XclAddress& XclImpCrn::GetAddress() const
+ {
+-    ScAddress aScPos( ScAddress::UNINITIALIZED );
+-    if( rRoot.GetAddressConverter().ConvertAddress( aScPos, maXclPos, nScTab, false ) )
+-    {
+-        switch( GetType() )
+-        {
+-            case EXC_CACHEDVAL_DOUBLE:
+-                rRoot.GetDoc().SetValue( aScPos.Col(), aScPos.Row(), aScPos.Tab(), GetValue() );
+-            break;
+-            case EXC_CACHEDVAL_STRING:
+-                rRoot.GetDoc().PutCell( aScPos, new ScStringCell( GetString() ) );
+-            break;
+-            case EXC_CACHEDVAL_BOOL:
+-            case EXC_CACHEDVAL_ERROR:
+-            {
+-                ScFormulaCell* pFmlaCell = new ScFormulaCell( rRoot.GetDocPtr(), aScPos, GetBoolErrFmla() );
+-                pFmlaCell->SetHybridDouble( GetBool() ? 1.0 : 0.0 );  // GetBool() returns false for error codes
+-                rRoot.GetDoc().PutCell( aScPos, pFmlaCell );
+-            }
+-            break;
+-        }
+-    }
++    return maXclPos;
+ }
+ 
+ // Sheet in an external document ==============================================
+@@ -383,13 +389,40 @@ void XclImpSupbookTab::ReadCrn( XclImpStream& rStrm, const XclAddress& rXclPos )
+     maCrnList.Append( new XclImpCrn( rStrm, rXclPos ) );
+ }
+ 
+-void XclImpSupbookTab::CreateAndFillTable( const XclImpRoot& rRoot,
+-        const String& rAbsUrl, const String& rFilterName, const String& rFilterOpt )
++void XclImpSupbookTab::LoadCachedValues(ScExternalRefCache::Table* pCacheTable)
+ {
+-    if( mnScTab == SCTAB_INVALID )
+-        if( rRoot.GetDoc().InsertLinkedEmptyTab( mnScTab, rAbsUrl, rFilterName, rFilterOpt, maTabName ) )
+-            for( const XclImpCrn* pCrn = maCrnList.First(); pCrn; pCrn = maCrnList.Next() )
+-                pCrn->SetCell( rRoot, mnScTab );
++    if (maCrnList.Empty())
++        return;
++
++    for (XclImpCrn* p = maCrnList.First(); p; p = maCrnList.Next())
++    {
++        const XclAddress& rAddr = p->GetAddress();
++        switch (p->GetType())
++        {
++            case EXC_CACHEDVAL_BOOL:
++            break;
++            case EXC_CACHEDVAL_DOUBLE:
++            {
++                double f = p->GetValue();
++                ScExternalRefCache::TokenRef pToken(new ScDoubleToken(f));
++                pCacheTable->setCell(rAddr.mnRow, rAddr.mnCol, pToken);
++            }
++            break;
++            case EXC_CACHEDVAL_EMPTY:
++            break;
++            case EXC_CACHEDVAL_ERROR:
++            break;
++            case EXC_CACHEDVAL_STRING:
++            {
++                const String& rStr = p->GetString();
++                ScExternalRefCache::TokenRef pToken(new ScStringToken(rStr));
++                pCacheTable->setCell(rAddr.mnRow, rAddr.mnCol, pToken);
++            }
++            break;
++            default:
++                ;
++        }
++    }
+ }
+ 
+ // External document (SUPBOOK) ================================================
+@@ -453,25 +486,9 @@ void XclImpSupbook::ReadCrn( XclImpStream& rStrm )
+     }
+ }
+ 
+-void XclImpSupbook::ReadExternname( XclImpStream& rStrm )
+-{
+-    maExtNameList.Append( new XclImpExtName( rStrm, meType == EXC_SBTYPE_ADDIN ) );
+-}
+-
+-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;
+-}
+-
+-SCTAB XclImpSupbook::GetScTabNum( const String& rTabName ) const
++void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+ {
+-    for( const XclImpSupbookTab* pSBTab = maSupbTabList.First(); pSBTab; pSBTab = maSupbTabList.Next() )
+-        if( pSBTab->GetTabName() == rTabName )
+-            return pSBTab->GetScTab();
+-    return SCTAB_INVALID;
++    maExtNameList.Append( new XclImpExtName( *this, rStrm, meType == EXC_SBTYPE_ADDIN, pFormulaConv ) );
+ }
+ 
+ const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
+@@ -492,20 +509,46 @@ const String& XclImpSupbook::GetMacroName( sal_uInt16 nXclNameIdx ) const
+     return (pName && pName->IsVBName()) ? pName->GetScName() : EMPTY_STRING;
+ }
+ 
+-void XclImpSupbook::CreateTables( sal_uInt16 nSBTabFirst, sal_uInt16 nSBTabLast )
++const String& XclImpSupbook::GetTabName( sal_uInt16 nXtiTab ) const
+ {
+-    if( (meType == EXC_SBTYPE_EXTERN) && (GetExtDocOptions().GetDocSettings().mnLinkCnt == 0) && GetDocShell() )
++    if (maSupbTabList.Empty())
++        return EMPTY_STRING;
++
++    sal_uInt16 i = 0;
++    for (XclImpSupbookTab* p = maSupbTabList.First(); p; p = maSupbTabList.Next(), ++i)
+     {
+-        String aAbsUrl( ScGlobal::GetAbsDocName( maXclUrl, GetDocShell() ) );
++        if (i == nXtiTab)
++            return p->GetTabName();
++    }
++
++    return EMPTY_STRING;
++}
++
++sal_uInt16 XclImpSupbook::GetTabCount() const
++{
++    return ulimit_cast<sal_uInt16>(maSupbTabList.Count());
++}
++
++void XclImpSupbook::LoadCachedValues()
++{
++    if (meType != EXC_SBTYPE_EXTERN || GetExtDocOptions().GetDocSettings().mnLinkCnt > 0)
++        return;
++
++    String aAbsUrl( ScGlobal::GetAbsDocName(maXclUrl, GetDocShell()) );
+ 
+-        // get filter name for external document
+-        if( !maFilterName.Len() )
+-            ScDocumentLoader::GetFilterName( aAbsUrl, maFilterName, maFilterOpt, FALSE, FALSE );
++    ScExternalRefManager* pRefMgr = GetRoot().GetDoc().GetExternalRefManager();
++    sal_uInt16 nFileId = pRefMgr->getExternalFileId(aAbsUrl);
+ 
+-        // create tables
+-        for( sal_uInt16 nSBTab = nSBTabFirst; nSBTab <= nSBTabLast; ++nSBTab )
+-            if( XclImpSupbookTab* pSBTab = maSupbTabList.GetObject( nSBTab ) )
+-                pSBTab->CreateAndFillTable( GetRoot(), aAbsUrl, maFilterName, maFilterOpt );
++    sal_uInt16 nCount = maSupbTabList.Count();
++    for (sal_uInt16 i = 0; i < nCount; ++i)
++    {
++        XclImpSupbookTab* pTab = maSupbTabList.GetObject(i);
++        if (!pTab)
++            return;
++        
++        const String& rTabName = pTab->GetTabName();
++        ScExternalRefCache::Table* pCacheTable = pRefMgr->getCacheTable(nFileId, rTabName, true);
++        pTab->LoadCachedValues(pCacheTable);
+     }
+ }
+ 
+@@ -531,7 +574,7 @@ void XclImpLinkManagerImpl::ReadExternsheet( XclImpStream& rStrm )
+         --nXtiCount;
+     }
+ 
+-    CreateTables();
++    LoadCachedValues();
+ }
+ 
+ void XclImpLinkManagerImpl::ReadSupbook( XclImpStream& rStrm )
+@@ -551,10 +594,10 @@ void XclImpLinkManagerImpl::ReadCrn( XclImpStream& rStrm )
+         pSupbook->ReadCrn( rStrm );
+ }
+ 
+-void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm )
++void XclImpLinkManagerImpl::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+ {
+     if( XclImpSupbook* pSupbook = maSupbookList.Last() )
+-        pSupbook->ReadExternname( rStrm );
++        pSupbook->ReadExternname( rStrm, pFormulaConv );
+ }
+ 
+ bool XclImpLinkManagerImpl::IsSelfRef( sal_uInt16 nXtiIndex ) const
+@@ -568,10 +611,10 @@ bool XclImpLinkManagerImpl::GetScTabRange(
+ {
+     if( const XclImpXti* pXti = maXtiList.GetObject( nXtiIndex ) )
+     {
+-        if( const XclImpSupbook* pSupbook = maSupbookList.GetObject( pXti->mnSupbook ) )
++        if (maSupbookList.GetObject(pXti->mnSupbook))
+         {
+-            rnFirstScTab = pSupbook->GetScTabNum( pXti->mnSBTabFirst );
+-            rnLastScTab = pSupbook->GetScTabNum( pXti->mnSBTabLast );
++            rnFirstScTab = pXti->mnSBTabFirst;
++            rnLastScTab  = pXti->mnSBTabLast;
+             return true;
+         }
+     }
+@@ -584,6 +627,20 @@ const XclImpExtName* XclImpLinkManagerImpl::GetExternName( sal_uInt16 nXtiIndex,
+     return pSupbook ? pSupbook->GetExternName( nExtName ) : 0;
+ }
+ 
++const String* XclImpLinkManagerImpl::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
++{
++    const XclImpSupbook* p = GetSupbook( nXtiIndex );
++    if (!p)
++        return NULL;
++    return &p->GetXclUrl();
++}
++
++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 );
+@@ -596,12 +653,6 @@ const String& XclImpLinkManagerImpl::GetMacroName( sal_uInt16 nExtSheet, sal_uIn
+     return pSupbook ? pSupbook->GetMacroName( nExtName ) : EMPTY_STRING;
+ }
+ 
+-SCTAB XclImpLinkManagerImpl::GetScTab( const String& rUrl, const String& rTabName ) const
+-{
+-    const XclImpSupbook* pSupbook = GetSupbook( rUrl );
+-    return pSupbook ? pSupbook->GetScTabNum( rTabName ) : SCTAB_INVALID;
+-}
+-
+ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( sal_uInt32 nXtiIndex ) const
+ {
+     const XclImpXti* pXti = maXtiList.GetObject( nXtiIndex );
+@@ -616,26 +667,17 @@ const XclImpSupbook* XclImpLinkManagerImpl::GetSupbook( const String& rUrl ) con
+     return 0;
+ }
+ 
+-void XclImpLinkManagerImpl::CreateTables()
++void XclImpLinkManagerImpl::LoadCachedValues()
+ {
+-    DBG_ASSERT( !mbCreated, "XclImpLinkManager::CreateTables - multiple call" );
+-    if( mbCreated ) return;
++    // Read all CRN records which can be accessed via XclImpSupbook, and store 
++    // the cached values to the external reference manager.
+ 
+-    sal_uInt16 nSBTabFirst, nSBTabLast;
+     sal_uInt32 nCount = maSupbookList.Count();
+-
+-    for( sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook )
++    for (sal_uInt16 nSupbook = 0; nSupbook < nCount; ++nSupbook)
+     {
+-        XclImpSupbook* pSupbook = maSupbookList.GetObject( nSupbook );
+-        bool bLoop = FindNextTabRange( nSBTabFirst, nSBTabLast, nSupbook, 0 );
+-        while( bLoop && pSupbook )
+-        {
+-            pSupbook->CreateTables( nSBTabFirst, nSBTabLast );
+-            // #96263# don't search again if last sheet == EXC_NOTAB
+-            bLoop = (nSBTabLast != EXC_NOTAB) && FindNextTabRange( nSBTabFirst, nSBTabLast, nSupbook, nSBTabLast + 1 );
+-        }
++        XclImpSupbook* pSupbook = maSupbookList.GetObject(nSupbook);
++        pSupbook->LoadCachedValues();
+     }
+-    mbCreated = true;
+ }
+ 
+ bool XclImpLinkManagerImpl::FindNextTabRange(
+@@ -686,9 +728,9 @@ void XclImpLinkManager::ReadCrn( XclImpStream& rStrm )
+     mxImpl->ReadCrn( rStrm );
+ }
+ 
+-void XclImpLinkManager::ReadExternname( XclImpStream& rStrm )
++void XclImpLinkManager::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv )
+ {
+-    mxImpl->ReadExternname( rStrm );
++    mxImpl->ReadExternname( rStrm, pFormulaConv );
+ }
+ 
+ bool XclImpLinkManager::IsSelfRef( sal_uInt16 nXtiIndex ) const
+@@ -707,6 +749,16 @@ const XclImpExtName* XclImpLinkManager::GetExternName( sal_uInt16 nXtiIndex, sal
+     return mxImpl->GetExternName( nXtiIndex, nExtName );
+ }
+ 
++const String* XclImpLinkManager::GetSupbookUrl( sal_uInt16 nXtiIndex ) const
++{
++    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 );
+@@ -717,10 +769,5 @@ const String& XclImpLinkManager::GetMacroName( sal_uInt16 nExtSheet, sal_uInt16
+     return mxImpl->GetMacroName( nExtSheet, nExtName );
+ }
+ 
+-SCTAB XclImpLinkManager::GetScTab( const String& rUrl, const String& rTabName ) const
+-{
+-    return mxImpl->GetScTab( rUrl, rTabName );
+-}
+-
+ // ============================================================================
+ 
+diff --git sc/source/filter/inc/XclImpChangeTrack.hxx sc/source/filter/inc/XclImpChangeTrack.hxx
+index 2335c6c..60108cb 100644
+--- sc/source/filter/inc/XclImpChangeTrack.hxx
++++ sc/source/filter/inc/XclImpChangeTrack.hxx
+@@ -126,7 +126,7 @@ public:
+ 
+ 								// reads extended 3D ref info following the formulas, returns sc tab nums
+ 								// ( called by XclImpChTrFmlConverter::Read3DTabReference() )
+-	sal_Bool					Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab );
++	sal_Bool					Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo );
+ 
+ 	void						Apply();
+ };
+@@ -182,7 +182,7 @@ class XclImpChTrFmlConverter : public ExcelToSc8
+ private:
+ 	XclImpChangeTrack&			rChangeTrack;
+ 
+-    virtual BOOL                Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab );
++    virtual bool                Read3DTabReference( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo );
+ 
+ public:
+ 	inline						XclImpChTrFmlConverter(
+diff --git sc/source/filter/inc/excform.hxx sc/source/filter/inc/excform.hxx
+index 915dd98..3059d6d 100644
+--- sc/source/filter/inc/excform.hxx
++++ sc/source/filter/inc/excform.hxx
+@@ -35,6 +35,7 @@
+ #include "xiroot.hxx"
+ #include "formel.hxx"
+ 
++#include <vector>
+ 
+ class ScRangeList;
+ 
+@@ -64,6 +65,10 @@ public:
+                                  bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula );
+ 
+     virtual ConvErr     Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula );
++
++    virtual ConvErr     ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                           const String& rUrl, const ::std::vector<String>& rTabNames );
++
+     virtual BOOL        GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen );
+ 
+ 	void				GetDummy( const ScTokenArray*& );
+@@ -102,19 +107,32 @@ inline BOOL ExcelToSc::IsComplRowRange( const UINT16 nRow1, const UINT16 nRow2 )
+ 	return ( ( nRow1 & 0x3FFF ) == 0x0000 ) && ( ( nRow2 & 0x3FFF ) == 0x3FFF );
+ }
+ 
++// ============================================================================
+ 
+ class XclImpLinkManager;
+ 
+ class ExcelToSc8 : public ExcelToSc
+ {
++public:
++
++    struct ExternalTabInfo
++    {
++        String      maTabName;
++        sal_uInt16  mnFileId;
++        bool        mbExternal;
++
++        ExternalTabInfo();
++    };
++
+ private:
+     const XclImpLinkManager&    rLinkMan;
+ 
+     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( UINT16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo );
+ 
+ public:
+                         ExcelToSc8( const XclImpRoot& rRoot );
+@@ -124,6 +142,9 @@ public:
+ 
+     virtual ConvErr     Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula );
+ 
++    virtual ConvErr     ConvertExternName( const ScTokenArray*& rpArray, XclImpStream& rStrm, sal_Size nFormulaLen,
++                                           const String& rUrl, const ::std::vector<String>& rTabNames );
++
+ 	static inline BOOL	IsComplRowRange( const UINT16 nRow1, const UINT16 nRow2 );
+ 
+     virtual BOOL        GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen );
+diff --git sc/source/filter/inc/tokstack.hxx sc/source/filter/inc/tokstack.hxx
+index 89e955a..5bb6772 100644
+--- sc/source/filter/inc/tokstack.hxx
++++ sc/source/filter/inc/tokstack.hxx
+@@ -35,6 +35,8 @@
+ #include <tools/debug.hxx>
+ #include "compiler.hxx"
+ 
++#include <vector>
++
+ 
+ typedef OpCode DefTokenId;
+ // in PRODUCT version: ambiguity between OpCode (being USHORT) and UINT16
+@@ -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 +139,32 @@ class TokenPool
+ 		UINT16						nP_Matrix;
+ 		UINT16						nP_MatrixAkt;
+ 
++        /** for storage of external names */
++        struct ExtName
++        {
++            sal_uInt16  mnFileId;
++            String      maName;
++        };
++        ::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,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..ee53c3a 100644
+--- sc/source/filter/inc/xelink.hxx
++++ sc/source/filter/inc/xelink.hxx
+@@ -173,11 +173,19 @@ public:
+     /** Searches for a special EXTERNSHEET index for the own document. */
+     sal_uInt16          FindExtSheet( sal_Unicode cCode );
+ 
++    void                FindExtSheet( sal_uInt16 nFileId, const String& rTabName, sal_uInt16 nXclTabSpan,
++                                      sal_uInt16& rnExtSheet, sal_uInt16& rnFirstSBTab, sal_uInt16& rnLastSBTab, 
++                                      XclExpRefLogEntry* pRefLogEntry = NULL );
++
+     /** Stores the cell with the given address in a CRN record list. */
+     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 String& rTabName, const SingleRefData& 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 +201,10 @@ public:
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rApplic, const String& rTopic, const String& rItem );
+ 
++    bool                InsertExtName(
++                            sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rUrl,
++                            const String& rName, const ScTokenArray* pArray );
++
+     /** Writes the entire Link table. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
+diff --git sc/source/filter/inc/xilink.hxx sc/source/filter/inc/xilink.hxx
+index 0d547fe..3983e4d 100644
+--- sc/source/filter/inc/xilink.hxx
++++ sc/source/filter/inc/xilink.hxx
+@@ -107,6 +107,8 @@ enum XclImpExtNameType
+ // ----------------------------------------------------------------------------
+ 
+ class XclImpCachedMatrix;
++class ScTokenArray;
++class XclImpSupbook;
+ 
+ /** Stores contents of an external name.
+     @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */
+@@ -114,21 +116,26 @@ class XclImpExtName
+ {
+ public:
+     /** Reads the external name from the stream. */
+-    explicit            XclImpExtName( XclImpStream& rStrm, bool bAddIn = false );
++    explicit            XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, bool bAddIn = false, 
++                                       ExcelToSc* pFormulaConv = NULL );
+                         ~XclImpExtName();
+ 
+     /** Create and apply the cached list of this DDE Link to the document. */
+     void                CreateDdeData( ScDocument& rDoc,
+                             const String& rApplc, const String& rExtDoc ) const;
+ 
++    void                CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const;
++
+     inline XclImpExtNameType GetType() const { return meType; }
+     inline const String& GetName() const { return maName; }
+     inline sal_uInt32   GetStorageId() const { return mnStorageId; }
+ 
+ private:
+     typedef ::std::auto_ptr< XclImpCachedMatrix > XclImpCachedMatrixPtr;
++    typedef ::std::auto_ptr< ScTokenArray >       TokenArrayPtr;
+ 
+     XclImpCachedMatrixPtr mxDdeMatrix;      /// Cached results of the DDE link.
++    TokenArrayPtr       mxArray;            /// Formula tokens for external name.
+     String              maName;             /// The name of the external name.
+     sal_uInt32          mnStorageId;        /// Storage ID for OLE object storages.
+     XclImpExtNameType   meType;             /// Type of the external name.
+@@ -168,7 +175,7 @@ public:
+     /** Reads a CRN record and appends it to the current SUPBOOK. */
+     void                ReadCrn( XclImpStream& rStrm );
+     /** Reads an EXTERNNAME record and appends it to the current SUPBOOK. */
+-    void                ReadExternname( XclImpStream& rStrm );
++    void                ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv = NULL );
+ 
+     /** Returns true, if the specified XTI entry contains an internal reference. */
+     bool                IsSelfRef( sal_uInt16 nXtiIndex ) const;
+@@ -179,6 +186,11 @@ public:
+                             sal_uInt16 nXtiIndex ) const;
+     /** Returns the specified external name or 0 on error. */
+     const XclImpExtName* GetExternName( sal_uInt16 nXtiIndex, sal_uInt16 nExtName ) const;
++
++    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.
+@@ -187,10 +199,6 @@ public:
+     /** Returns the specified macro name or an empty string on error. */
+     const String&       GetMacroName( sal_uInt16 nExtSheet, sal_uInt16 nExtName ) const;
+ 
+-    /** 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;
+-
+ private:
+     typedef ::std::auto_ptr< XclImpLinkManagerImpl > XclImpLinkMgrImplPtr;
+     XclImpLinkMgrImplPtr mxImpl;
+diff --git sc/source/filter/xcl97/XclImpChangeTrack.cxx sc/source/filter/xcl97/XclImpChangeTrack.cxx
+index 022b472..a1efd3e 100644
+--- sc/source/filter/xcl97/XclImpChangeTrack.cxx
++++ sc/source/filter/xcl97/XclImpChangeTrack.cxx
+@@ -40,6 +40,7 @@
+ #include "chgtrack.hxx"
+ #include "xihelper.hxx"
+ #include "xilink.hxx"
++#include "externalrefmgr.hxx"
+ 
+ //___________________________________________________________________
+ // class XclImpChangeTrack
+@@ -153,10 +154,11 @@ sal_Bool XclImpChangeTrack::CheckRecord( sal_uInt16 nOpCode )
+ 	return aRecHeader.nIndex != 0;
+ }
+ 
+-sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab )
++sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo )
+ {
+ 	if( LookAtuInt8() == 0x01 )
+ 	{
++        rExtInfo.mbExternal = false;
+ 		// internal ref - read tab num and return sc tab num (position in TABID list)
+         pStrm->Ignore( 3 );
+         rFirstTab = static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) );
+@@ -176,7 +178,13 @@ 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 ));
++
++        rExtInfo.mbExternal = true;
++        ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++        pRefMgr->convertToAbsName(aUrl);
++        rExtInfo.mnFileId = pRefMgr->getExternalFileId(aUrl);
++        rExtInfo.maTabName = aTabName;
++        rFirstTab = rLastTab = 0;
+ 	}
+ 	return sal_True;
+ }
+@@ -329,7 +337,8 @@ void XclImpChangeTrack::ReadChTrCellContent()
+ 	if( CheckRecord( EXC_CHTR_OP_CELL ) )
+ 	{
+ 		ScAddress aPosition;
+-		aPosition.SetTab( ReadTabNum() );
++		SCTAB nTab = ReadTabNum();
++		aPosition.SetTab( nTab );
+ 		sal_uInt16 nValueType;
+ 		*pStrm >> nValueType;
+ 		sal_uInt16 nOldValueType = (nValueType >> 3) & EXC_CHTR_TYPE_MASK;
+@@ -490,9 +499,9 @@ XclImpChTrFmlConverter::~XclImpChTrFmlConverter()
+ }
+ 
+ // virtual, called from ExcToSc8::Convert()
+-BOOL XclImpChTrFmlConverter::Read3DTabReference( XclImpStream& rStrm, SCTAB& rFirstTab, SCTAB& rLastTab )
++bool XclImpChTrFmlConverter::Read3DTabReference( UINT16 /*nIxti*/, SCTAB& rFirstTab, SCTAB& rLastTab, 
++												 ExternalTabInfo& rExtInfo )
+ {
+-    rStrm.Ignore( 2 );
+-	return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab );
++	return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab, rExtInfo );
+ }
+ 
+diff --git sc/source/filter/xml/XMLDDELinksContext.cxx sc/source/filter/xml/XMLDDELinksContext.cxx
+index 81ec1d2..4ab6982 100644
+--- sc/source/filter/xml/XMLDDELinksContext.cxx
++++ sc/source/filter/xml/XMLDDELinksContext.cxx
+@@ -46,6 +46,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ //------------------------------------------------------------------
+ 
+diff --git sc/source/filter/xml/XMLTableShapeImportHelper.cxx sc/source/filter/xml/XMLTableShapeImportHelper.cxx
+index bb6fe74..219b5cc 100644
+--- sc/source/filter/xml/XMLTableShapeImportHelper.cxx
++++ sc/source/filter/xml/XMLTableShapeImportHelper.cxx
+@@ -49,6 +49,7 @@
+ 
+ using namespace ::com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ XMLTableShapeImportHelper::XMLTableShapeImportHelper(
+ 		ScXMLImport& rImp, SvXMLImportPropertyMapper *pImpMapper ) :
+diff --git sc/source/filter/xml/XMLTrackedChangesContext.cxx sc/source/filter/xml/XMLTrackedChangesContext.cxx
+index a779ddf..3b2ea17 100644
+--- sc/source/filter/xml/XMLTrackedChangesContext.cxx
++++ sc/source/filter/xml/XMLTrackedChangesContext.cxx
+@@ -48,6 +48,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ //-----------------------------------------------------------------------------
+ 
+diff --git sc/source/filter/xml/makefile.mk sc/source/filter/xml/makefile.mk
+index 68ee10b..d44da6b 100644
+--- sc/source/filter/xml/makefile.mk
++++ sc/source/filter/xml/makefile.mk
+@@ -57,6 +57,7 @@ CXXFILES = \
+ 		xmlexprt.cxx \
+ 		xmlbodyi.cxx \
+ 		xmltabi.cxx \
++		xmlexternaltabi.cxx \
+ 		xmlrowi.cxx \
+ 		xmlcelli.cxx \
+ 		xmlconti.cxx \
+@@ -106,6 +107,7 @@ SLOFILES =  \
+ 		$(SLO)$/xmlexprt.obj \
+ 		$(SLO)$/xmlbodyi.obj \
+ 		$(SLO)$/xmltabi.obj \
++		$(SLO)$/xmlexternaltabi.obj \
+ 		$(SLO)$/xmlrowi.obj \
+ 		$(SLO)$/xmlcelli.obj \
+ 		$(SLO)$/xmlconti.obj \
+diff --git sc/source/filter/xml/xmlbodyi.cxx sc/source/filter/xml/xmlbodyi.cxx
+index 5f3545a..76780d3 100644
+--- sc/source/filter/xml/xmlbodyi.cxx
++++ sc/source/filter/xml/xmlbodyi.cxx
+@@ -67,6 +67,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ //------------------------------------------------------------------
+ 
+diff --git sc/source/filter/xml/xmlcelli.cxx sc/source/filter/xml/xmlcelli.cxx
+index 92eb208..a990e54 100644
+--- sc/source/filter/xml/xmlcelli.cxx
++++ sc/source/filter/xml/xmlcelli.cxx
+@@ -146,185 +146,131 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport,
+ 	rtl::OUString aLocalName;
+ 	rtl::OUString* pStyleName = NULL;
+ 	rtl::OUString* pCurrencySymbol = NULL;
+-	for( sal_Int16 i=0; i < nAttrCount; ++i )
++    const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap();
++	for (sal_Int16 i = 0; i < nAttrCount; ++i)
+ 	{
+-		sal_uInt16 nPrefix = rXMLImport.GetNamespaceMap().GetKeyByAttrName(
+-											xAttrList->getNameByIndex( i ), &aLocalName );
+-    	const rtl::OUString& sValue(xAttrList->getValueByIndex( i ));
++        sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(
++            xAttrList->getNameByIndex(i), &aLocalName);
+ 
+-		if (nPrefix == XML_NAMESPACE_TABLE)
+-		{
+-            sal_uInt32 nLength(aLocalName.getLength());
+-
+-            switch (nLength)
++        const rtl::OUString& sValue = xAttrList->getValueByIndex(i);
++        sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName);
++        switch (nToken)
++        {
++            case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME:
++                pStyleName = new rtl::OUString(sValue);
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME:
++                DBG_ASSERT(!pContentValidationName, "here should be only one Validation Name");
++                pContentValidationName = new rtl::OUString(sValue);
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS:
++                bIsMerged = sal_True;
++                nMergedRows = sValue.toInt32();
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS:
++                bIsMerged = sal_True;
++                nMergedCols = sValue.toInt32();
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS:
++                bIsMatrix = sal_True;
++                nMatrixCols = sValue.toInt32();
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS:
++                bIsMatrix = sal_True;
++                nMatrixRows = sValue.toInt32();
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED:
++                nCellsRepeated = std::max( sValue.toInt32(), (sal_Int32) 1 );
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
++                nCellType = GetScImport().GetCellType(sValue);
++                bIsEmpty = sal_False;
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
+             {
+-            case 7 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_FORMULA))
+-			        {
+-				        if (sValue.getLength())
+-				        {
+-					        DBG_ASSERT(!pOUFormula, "here should be only one formula");
+-                            DELETEZ( pOUFormula);
+-                            rtl::OUString sFormula;
+-				            sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap().
+-						            _GetKeyByAttrName( sValue, &sFormula, sal_False );
+-
+-                            if (ScXMLImport::IsAcceptedFormulaNamespace(
+-                                        nFormulaPrefix, sValue, eGrammar,
+-                                        eStorageGrammar))
+-                            {
+-                                // Namespaces we accept.
+-                                pOUFormula = new rtl::OUString( sFormula);
+-                            }
+-                            else
+-                            {
+-                                // No namespace => entire string.
+-                                // Also unknown namespace included in formula,
+-                                // so hopefully will result in string or
+-                                // compile error.
+-                                pOUFormula = new rtl::OUString( sValue);
+-                            }
+-				        }
+-			        }
+-                }
+-                break;
+-            case 10 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_STYLE_NAME))
+-				        pStyleName = new rtl::OUString(sValue);
+-                }
+-                break;
+-            case 19 :
++                if (sValue.getLength())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_NUMBER_ROWS_SPANNED))
+-			        {
+-				        bIsMerged = sal_True;
+-				        nMergedRows = sValue.toInt32();
+-			        }
++                    rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue);
++                    bIsEmpty = sal_False;
+                 }
+-                break;
+-            case 22 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_NUMBER_COLUMNS_SPANNED))
+-			        {
+-				        bIsMerged = sal_True;
+-				        nMergedCols = sValue.toInt32();
+-			        }
+-                }
+-                break;
+-            case 23 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_NUMBER_COLUMNS_REPEATED))
+-                        nCellsRepeated = std::max( sValue.toInt32(), (sal_Int32) 1 );
+-                    else if (IsXMLToken(aLocalName, XML_CONTENT_VALIDATION_NAME))
+-			        {
+-				        DBG_ASSERT(!pContentValidationName, "here should be only one Validation Name");
+-				        pContentValidationName = new rtl::OUString(sValue);
+-			        }
+-                }
+-                break;
+-            case 26 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_NUMBER_MATRIX_ROWS_SPANNED))
+-			        {
+-				        bIsMatrix = sal_True;
+-				        nMatrixRows = sValue.toInt32();
+-			        }
+-                }
+-                break;
+-            case 29 :
+-                {
+-			        if (IsXMLToken(aLocalName, XML_NUMBER_MATRIX_COLUMNS_SPANNED))
+-			        {
+-				        bIsMatrix = sal_True;
+-				        nMatrixCols = sValue.toInt32();
+-			        }
+-                }
+-                break;
+             }
+-        }
+-		else if (nPrefix == XML_NAMESPACE_OFFICE)
+-		{
+-            sal_uInt32 nLength(aLocalName.getLength());
+-
+-            switch (nLength)
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE:
+             {
+-            case 5 :
++                if (sValue.getLength() && rXMLImport.SetNullDateOnUnitConverter())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_VALUE))
+-			        {
+-				        if (sValue.getLength())
+-				        {
+-					        rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue);
+-					        bIsEmpty = sal_False;
+-				        }
+-			        }
++                    rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, sValue);
++                    bIsEmpty = sal_False;
+                 }
+-                break;
+-            case 8 :
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE:
++            {
++                if (sValue.getLength())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_CURRENCY))
+-				        pCurrencySymbol = new rtl::OUString(sValue);
++                    rXMLImport.GetMM100UnitConverter().convertTime(fValue, sValue);
++                    bIsEmpty = sal_False;
+                 }
+-                break;
+-            case 10 :
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE:
++            {
++                if (sValue.getLength())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_VALUE_TYPE))
+-			        {
+-				        nCellType = GetCellType(sValue);
+-				        bIsEmpty = sal_False;
+-			        }
+-		            else if (IsXMLToken(aLocalName, XML_DATE_VALUE))
+-		            {
+-			            if (sValue.getLength() && rXMLImport.SetNullDateOnUnitConverter())
+-			            {
+-				            rXMLImport.GetMM100UnitConverter().convertDateTime(fValue, sValue);
+-				            bIsEmpty = sal_False;
+-			            }
+-		            }
+-		            else if (IsXMLToken(aLocalName, XML_TIME_VALUE))
+-		            {
+-			            if (sValue.getLength())
+-			            {
+-				            rXMLImport.GetMM100UnitConverter().convertTime(fValue, sValue);
+-				            bIsEmpty = sal_False;
+-			            }
+-		            }
++                    DBG_ASSERT(!pOUTextValue, "here should be only one string value");
++                    pOUTextValue = new rtl::OUString(sValue);
++                    bIsEmpty = sal_False;
+                 }
+-                break;
+-            case 12 :
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE:
++            {
++                if (sValue.getLength())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_STRING_VALUE))
+-			        {
+-				        if (sValue.getLength())
+-				        {
+-					        DBG_ASSERT(!pOUTextValue, "here should be only one string value");
+-					        pOUTextValue = new rtl::OUString(sValue);
+-					        bIsEmpty = sal_False;
+-				        }
+-			        }
++                    if ( IsXMLToken(sValue, XML_TRUE) )
++                        fValue = 1.0;
++                    else if ( IsXMLToken(sValue, XML_FALSE) )
++                        fValue = 0.0;
++                    else
++                        rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue);
++                    bIsEmpty = sal_False;
+                 }
+-                break;
+-            case 13 :
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA:
++            {
++                if (sValue.getLength())
+                 {
+-			        if (IsXMLToken(aLocalName, XML_BOOLEAN_VALUE))
+-			        {
+-				        if (sValue.getLength())
+-				        {
+-					        if ( IsXMLToken(sValue, XML_TRUE) )
+-						        fValue = 1.0;
+-					        else if ( IsXMLToken(sValue, XML_FALSE) )
+-						        fValue = 0.0;
+-                            else
+-                                rXMLImport.GetMM100UnitConverter().convertDouble(fValue, sValue);
+-					        bIsEmpty = sal_False;
+-				        }
+-			        }
++                    DBG_ASSERT(!pOUFormula, "here should be only one formula");
++                    DELETEZ( pOUFormula);
++                    rtl::OUString sFormula;
++                    sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap().
++                            _GetKeyByAttrName( sValue, &sFormula, sal_False );
++
++                    if (ScXMLImport::IsAcceptedFormulaNamespace(
++                                nFormulaPrefix, sValue, eGrammar,
++                                eStorageGrammar))
++                    {
++                        // Namespaces we accept.
++                        pOUFormula = new rtl::OUString( sFormula);
++                    }
++                    else
++                    {
++                        // No namespace => entire string.
++                        // Also unknown namespace included in formula,
++                        // so hopefully will result in string or
++                        // compile error.
++                        pOUFormula = new rtl::OUString( sValue);
++                    }
+                 }
+-                break;
+             }
+-		}
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY:
++                pCurrencySymbol = new rtl::OUString(sValue);
++            break;
++            default:
++                ;
++        }
+ 	}
+ 	if (pOUFormula)
+ 	{
+@@ -335,32 +281,6 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport,
+ 	rXMLImport.GetStylesImportHelper()->SetAttributes(pStyleName, pCurrencySymbol, nCellType);
+ }
+ 
+-sal_Int16 ScXMLTableRowCellContext::GetCellType(const rtl::OUString& sOUValue) const
+-{
+-	if (IsXMLToken(sOUValue, XML_FLOAT))
+-		return util::NumberFormat::NUMBER;
+-	else
+-		if (IsXMLToken(sOUValue, XML_STRING))
+-			return util::NumberFormat::TEXT;
+-		else
+-			if (IsXMLToken(sOUValue, XML_TIME))
+-				return util::NumberFormat::TIME;
+-			else
+-				if (IsXMLToken(sOUValue, XML_DATE))
+-					return util::NumberFormat::DATETIME;
+-				else
+-					if (IsXMLToken(sOUValue, XML_PERCENTAGE))
+-						return util::NumberFormat::PERCENT;
+-					else
+-						if (IsXMLToken(sOUValue, XML_CURRENCY))
+-							return util::NumberFormat::CURRENCY;
+-						else
+-							if (IsXMLToken(sOUValue, XML_BOOLEAN))
+-								return util::NumberFormat::LOGICAL;
+-							else
+-								return util::NumberFormat::UNDEFINED;
+-}
+-
+ ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
+ {
+ 	if (pOUTextValue)
+diff --git sc/source/filter/xml/xmlcelli.hxx sc/source/filter/xml/xmlcelli.hxx
+index b1de3ee..589077d 100644
+--- sc/source/filter/xml/xmlcelli.hxx
++++ sc/source/filter/xml/xmlcelli.hxx
+@@ -95,8 +95,6 @@ class ScXMLTableRowCellContext : public SvXMLImportContext
+ 	const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
+ 	ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
+ 
+-	sal_Int16 GetCellType(const rtl::OUString& sOUValue) const;
+-
+ 	sal_Bool IsMerged (const com::sun::star::uno::Reference <com::sun::star::table::XCellRange>& xCellRange,
+ 				const sal_Int32 nCol, const sal_Int32 nRow,
+ 				com::sun::star::table::CellRangeAddress& aCellAddress) const;
+diff --git sc/source/filter/xml/xmldpimp.cxx sc/source/filter/xml/xmldpimp.cxx
+index e29223a..604e04e 100644
+--- sc/source/filter/xml/xmldpimp.cxx
++++ sc/source/filter/xml/xmldpimp.cxx
+@@ -65,6 +65,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ //------------------------------------------------------------------
+ 
+diff --git sc/source/filter/xml/xmlexprt.cxx sc/source/filter/xml/xmlexprt.cxx
+index 441f463..535ed45 100644
+--- sc/source/filter/xml/xmlexprt.cxx
++++ sc/source/filter/xml/xmlexprt.cxx
+@@ -68,6 +68,7 @@
+ #include "convuno.hxx"
+ #include "postit.hxx"
+ #include "tabprotection.hxx"
++#include "externalrefmgr.hxx"
+ 
+ #include <xmloff/xmltoken.hxx>
+ #include <xmloff/xmlnmspe.hxx>
+@@ -129,6 +130,8 @@
+ 
+ #include <sfx2/objsh.hxx>
+ 
++#include <vector>
++
+ //! not found in unonames.hxx
+ #define SC_STANDARDFORMAT "StandardFormat"
+ #define SC_LAYERID "LayerID"
+@@ -152,6 +155,7 @@
+ using namespace rtl;
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::std::vector;
+ 
+ //----------------------------------------------------------------------------
+ 
+@@ -479,6 +483,12 @@ ScXMLExport::ScXMLExport(
+ 
+ 	if( (getExportFlags() & (EXPORT_STYLES|EXPORT_AUTOSTYLES|EXPORT_MASTERSTYLES|EXPORT_CONTENT) ) != 0 )
+     {
++        // This name is reserved for the external ref cache tables.  This
++        // should not conflict with user-defined styles since this name is
++        // used for a table style which is not available in the UI.
++        sExternalRefTabStyleName = rtl::OUString::createFromAscii("ta_extref");
++        GetAutoStylePool()->RegisterName(XML_STYLE_FAMILY_TABLE_TABLE, sExternalRefTabStyleName);
++
+         sAttrName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NAME));
+         sAttrStyleName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_STYLE_NAME));
+         sAttrColumnsRepeated = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_TABLE, GetXMLToken(XML_NUMBER_COLUMNS_REPEATED));
+@@ -1422,180 +1432,181 @@ void ScXMLExport::_ExportContent()
+ 		DBG_ERROR("no shared data setted");
+ 	}
+ 	ScXMLExportDatabaseRanges aExportDatabaseRanges(*this);
+-	if (!GetModel().is())
++    if (!GetModel().is())
+         return;
+ 
+-		uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
++    uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( GetModel(), uno::UNO_QUERY );
+     if ( !xSpreadDoc.is() )
+         return;
+ 
+-			uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
+-			if ( xIndex.is() )
+-			{
+-				//_GetNamespaceMap().ClearQNamesCache();
+-				pChangeTrackingExportHelper->CollectAndWriteChanges();
+-				WriteCalculationSettings(xSpreadDoc);
+-				sal_Int32 nTableCount(xIndex->getCount());
+-				ScMyAreaLinksContainer aAreaLinks;
+-				GetAreaLinks( xSpreadDoc, aAreaLinks );
+-				ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges());
+-				ScMyDetectiveOpContainer aDetectiveOpContainer;
+-				GetDetectiveOpList( aDetectiveOpContainer );
+-
+-				pCellStyles->Sort();
+-				pMergedRangesContainer->Sort();
+-				pSharedData->GetDetectiveObjContainer()->Sort();
+-
+-				pCellsItr->Clear();
+-				pCellsItr->SetShapes( pSharedData->GetShapesContainer() );
+-				pCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() );
+-				pCellsItr->SetMergedRanges( pMergedRangesContainer );
+-				pCellsItr->SetAreaLinks( &aAreaLinks );
+-				pCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges );
+-				pCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() );
+-				pCellsItr->SetDetectiveOp( &aDetectiveOpContainer );
+-
+-				if (nTableCount > 0)
+-					pValidationsContainer->WriteValidations(*this);
+-				WriteTheLabelRanges( xSpreadDoc );
+-				for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable)
+-				{
+-                    uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
+-					if (xTable.is())
+-					{
+-						xCurrentTable.set(xTable);
+-                        xCurrentTableCellRange.set(xTable, uno::UNO_QUERY);
+-						uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY );
+-						if ( xName.is() )
+-						{
+-                            nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable );
+-							rtl::OUString sOUTableName(xName->getName());
+-							AddAttribute(sAttrName, sOUTableName);
+-							AddAttribute(sAttrStyleName, aTableStyles[nTable]);
+-							uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY);
+-							if (xProtectable.is() && xProtectable->isProtected())
+-							{
+-								AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
+-								rtl::OUStringBuffer aBuffer;
+-								if (pDoc)
++    uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
++    if ( xIndex.is() )
++    {
++        //_GetNamespaceMap().ClearQNamesCache();
++        pChangeTrackingExportHelper->CollectAndWriteChanges();
++        WriteCalculationSettings(xSpreadDoc);
++        sal_Int32 nTableCount(xIndex->getCount());
++        ScMyAreaLinksContainer aAreaLinks;
++        GetAreaLinks( xSpreadDoc, aAreaLinks );
++        ScMyEmptyDatabaseRangesContainer aEmptyRanges(aExportDatabaseRanges.GetEmptyDatabaseRanges());
++        ScMyDetectiveOpContainer aDetectiveOpContainer;
++        GetDetectiveOpList( aDetectiveOpContainer );
++
++        pCellStyles->Sort();
++        pMergedRangesContainer->Sort();
++        pSharedData->GetDetectiveObjContainer()->Sort();
++
++        pCellsItr->Clear();
++        pCellsItr->SetShapes( pSharedData->GetShapesContainer() );
++        pCellsItr->SetNoteShapes( pSharedData->GetNoteShapes() );
++        pCellsItr->SetMergedRanges( pMergedRangesContainer );
++        pCellsItr->SetAreaLinks( &aAreaLinks );
++        pCellsItr->SetEmptyDatabaseRanges( &aEmptyRanges );
++        pCellsItr->SetDetectiveObj( pSharedData->GetDetectiveObjContainer() );
++        pCellsItr->SetDetectiveOp( &aDetectiveOpContainer );
++
++        if (nTableCount > 0)
++            pValidationsContainer->WriteValidations(*this);
++        WriteTheLabelRanges( xSpreadDoc );
++        for (sal_Int32 nTable = 0; nTable < nTableCount; ++nTable)
++        {
++            uno::Reference<sheet::XSpreadsheet> xTable(xIndex->getByIndex(nTable), uno::UNO_QUERY);
++            if (xTable.is())
++            {
++                xCurrentTable.set(xTable);
++                xCurrentTableCellRange.set(xTable, uno::UNO_QUERY);
++                uno::Reference<container::XNamed> xName (xTable, uno::UNO_QUERY );
++                if ( xName.is() )
++                {
++                    nCurrentTable = sal::static_int_cast<sal_uInt16>( nTable );
++                    rtl::OUString sOUTableName(xName->getName());
++                    AddAttribute(sAttrName, sOUTableName);
++                    AddAttribute(sAttrStyleName, aTableStyles[nTable]);
++                    uno::Reference<util::XProtectable> xProtectable (xTable, uno::UNO_QUERY);
++                    if (xProtectable.is() && xProtectable->isProtected())
++                    {
++                        AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE);
++                        rtl::OUStringBuffer aBuffer;
++                        if (pDoc)
++                        {
++                            ScTableProtection* pProtect = pDoc->GetTabProtection(static_cast<SCTAB>(nTable));
++                            if (pProtect)
++                                SvXMLUnitConverter::encodeBase64(aBuffer, pProtect->getPasswordHash(PASSHASH_OOO));
++                        }
++                        if (aBuffer.getLength())
++                            AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
++                    }
++                    rtl::OUString sPrintRanges;
++                    table::CellRangeAddress aColumnHeaderRange;
++                    sal_Bool bHasColumnHeader;
++                    GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges);
++                    if( sPrintRanges.getLength() )
++                        AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges );
++                    else if (!pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable)))
++                        AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE);
++                    SvXMLElementExport aElemT(*this, sElemTab, sal_True, sal_True);
++                    CheckAttrList();
++                    WriteTableSource();
++                    WriteScenario();
++                    uno::Reference<drawing::XDrawPage> xDrawPage;
++                    if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is())
++                    {
++                        ::xmloff::OOfficeFormsExport aForms(*this);
++                        GetFormExport()->exportForms( xDrawPage );
++                        sal_Bool bRet(GetFormExport()->seekPage( xDrawPage ));
++                        DBG_ASSERT( bRet, "OFormLayerXMLExport::seekPage failed!" );
++                        (void)bRet;     // avoid warning in product version
++                    }
++                    if (pSharedData->HasDrawPage())
++                    {
++                        GetShapeExport()->seekShapes(uno::Reference<drawing::XShapes>(pSharedData->GetDrawPage(nTable), uno::UNO_QUERY));
++                        WriteTableShapes();
++                    }
++                    table::CellRangeAddress aRange(GetEndAddress(xTable, nTable));
++                    pSharedData->SetLastColumn(nTable, aRange.EndColumn);
++                    pSharedData->SetLastRow(nTable, aRange.EndRow);
++                    pCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable);
++                    pGroupColumns->NewTable();
++                    pGroupRows->NewTable();
++                    FillColumnRowGroups();
++                    if (bHasColumnHeader)
++                        pSharedData->SetLastColumn(nTable, aColumnHeaderRange.EndColumn);
++                    bRowHeaderOpen = sal_False;
++                    if (bHasRowHeader)
++                        pSharedData->SetLastRow(nTable, aRowHeaderRange.EndRow);
++                    pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable),
++                        pSharedData->GetLastColumn(nTable), pCellStyles, pDoc);
++                    pRowFormatRanges->SetRowDefaults(pDefaults->GetRowDefaults());
++                    pRowFormatRanges->SetColDefaults(pDefaults->GetColDefaults());
++                    pCellStyles->SetRowDefaults(pDefaults->GetRowDefaults());
++                    pCellStyles->SetColDefaults(pDefaults->GetColDefaults());
++                    ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader);
++                    sal_Bool bIsFirst(sal_True);
++                    sal_Int32 nEqualCells(0);
++                    ScMyCell aCell;
++                    ScMyCell aPrevCell;
++                    while(pCellsItr->GetNext(aCell, pCellStyles))
++                    {
++                        if (bIsFirst)
++                        {
++                            ExportFormatRanges(0, 0, aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable);
++                            aPrevCell = aCell;
++                            bIsFirst = sal_False;
++                        }
++                        else
++                        {
++                            if ((aPrevCell.aCellAddress.Row == aCell.aCellAddress.Row) &&
++                                (aPrevCell.aCellAddress.Column + nEqualCells + 1 == aCell.aCellAddress.Column))
++                            {
++                                if(IsCellEqual(aPrevCell, aCell))
++                                    ++nEqualCells;
++                                else
+                                 {
+-                                    ScTableProtection* pProtect = pDoc->GetTabProtection(static_cast<SCTAB>(nTable));
+-                                    if (pProtect)
+-                                        SvXMLUnitConverter::encodeBase64(aBuffer, pProtect->getPasswordHash(PASSHASH_OOO));
++                                    SetRepeatAttribute(nEqualCells);
++                                    WriteCell(aPrevCell);
++                                    nEqualCells = 0;
++                                    aPrevCell = aCell;
+                                 }
+-								if (aBuffer.getLength())
+-									AddAttribute(XML_NAMESPACE_TABLE, XML_PROTECTION_KEY, aBuffer.makeStringAndClear());
+-							}
+-							rtl::OUString sPrintRanges;
+-							table::CellRangeAddress aColumnHeaderRange;
+-							sal_Bool bHasColumnHeader;
+-                            GetColumnRowHeader(bHasColumnHeader, aColumnHeaderRange, bHasRowHeader, aRowHeaderRange, sPrintRanges);
+-							if( sPrintRanges.getLength() )
+-								AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT_RANGES, sPrintRanges );
+-                            else if (!pDoc->IsPrintEntireSheet(static_cast<SCTAB>(nTable)))
+-                                AddAttribute( XML_NAMESPACE_TABLE, XML_PRINT, XML_FALSE);
+-							SvXMLElementExport aElemT(*this, sElemTab, sal_True, sal_True);
+-							CheckAttrList();
+-							WriteTableSource();
+-							WriteScenario();
+-							uno::Reference<drawing::XDrawPage> xDrawPage;
+-							if (pSharedData->HasForm(nTable, xDrawPage) && xDrawPage.is())
+-							{
+-								::xmloff::OOfficeFormsExport aForms(*this);
+-								GetFormExport()->exportForms( xDrawPage );
+-								sal_Bool bRet(GetFormExport()->seekPage( xDrawPage ));
+-								DBG_ASSERT( bRet, "OFormLayerXMLExport::seekPage failed!" );
+-                                (void)bRet;     // avoid warning in product version
+-							}
+-							if (pSharedData->HasDrawPage())
+-							{
+-								GetShapeExport()->seekShapes(uno::Reference<drawing::XShapes>(pSharedData->GetDrawPage(nTable), uno::UNO_QUERY));
+-								WriteTableShapes();
+-							}
+-							table::CellRangeAddress aRange(GetEndAddress(xTable, nTable));
+-							pSharedData->SetLastColumn(nTable, aRange.EndColumn);
+-							pSharedData->SetLastRow(nTable, aRange.EndRow);
+-							pCellsItr->SetCurrentTable(static_cast<SCTAB>(nTable), xCurrentTable);
+-							pGroupColumns->NewTable();
+-							pGroupRows->NewTable();
+-							FillColumnRowGroups();
+-							if (bHasColumnHeader)
+-								pSharedData->SetLastColumn(nTable, aColumnHeaderRange.EndColumn);
+-							bRowHeaderOpen = sal_False;
+-							if (bHasRowHeader)
+-								pSharedData->SetLastRow(nTable, aRowHeaderRange.EndRow);
+-							pDefaults->FillDefaultStyles(nTable, pSharedData->GetLastRow(nTable),
+-								pSharedData->GetLastColumn(nTable), pCellStyles, pDoc);
+-							pRowFormatRanges->SetRowDefaults(pDefaults->GetRowDefaults());
+-							pRowFormatRanges->SetColDefaults(pDefaults->GetColDefaults());
+-							pCellStyles->SetRowDefaults(pDefaults->GetRowDefaults());
+-							pCellStyles->SetColDefaults(pDefaults->GetColDefaults());
+-							ExportColumns(nTable, aColumnHeaderRange, bHasColumnHeader);
+-							sal_Bool bIsFirst(sal_True);
+-							sal_Int32 nEqualCells(0);
+-							ScMyCell aCell;
+-							ScMyCell aPrevCell;
+-							while(pCellsItr->GetNext(aCell, pCellStyles))
+-							{
+-								if (bIsFirst)
+-								{
+-									ExportFormatRanges(0, 0, aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable);
+-									aPrevCell = aCell;
+-									bIsFirst = sal_False;
+-								}
+-								else
+-								{
+-									if ((aPrevCell.aCellAddress.Row == aCell.aCellAddress.Row) &&
+-										(aPrevCell.aCellAddress.Column + nEqualCells + 1 == aCell.aCellAddress.Column))
+-									{
+-										if(IsCellEqual(aPrevCell, aCell))
+-											++nEqualCells;
+-										else
+-										{
+-											SetRepeatAttribute(nEqualCells);
+-											WriteCell(aPrevCell);
+-											nEqualCells = 0;
+-											aPrevCell = aCell;
+-										}
+-									}
+-									else
+-									{
+-										SetRepeatAttribute(nEqualCells);
+-										WriteCell(aPrevCell);
+-										ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row,
+-											aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable);
+-										nEqualCells = 0;
+-										aPrevCell = aCell;
+-									}
+-								}
+-							}
+-							if (!bIsFirst)
+-							{
+-								SetRepeatAttribute(nEqualCells);
+-								WriteCell(aPrevCell);
+-								ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row,
+-									pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
+-							}
+-							else
+-								ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
+-							CloseRow(pSharedData->GetLastRow(nTable));
+-							nEqualCells = 0;
+-						}
+-					}
+-                    RemoveTempAnnotaionShape(nTable);
++                            }
++                            else
++                            {
++                                SetRepeatAttribute(nEqualCells);
++                                WriteCell(aPrevCell);
++                                ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row,
++                                    aCell.aCellAddress.Column - 1, aCell.aCellAddress.Row, nTable);
++                                nEqualCells = 0;
++                                aPrevCell = aCell;
++                            }
++                        }
++                    }
++                    if (!bIsFirst)
++                    {
++                        SetRepeatAttribute(nEqualCells);
++                        WriteCell(aPrevCell);
++                        ExportFormatRanges(aPrevCell.aCellAddress.Column + nEqualCells + 1, aPrevCell.aCellAddress.Row,
++                            pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
++                    }
++                    else
++                        ExportFormatRanges(0, 0, pSharedData->GetLastColumn(nTable), pSharedData->GetLastRow(nTable), nTable);
++                    CloseRow(pSharedData->GetLastRow(nTable));
++                    nEqualCells = 0;
++                }
++            }
++            RemoveTempAnnotaionShape(nTable);
+ 
+-					IncrementProgressBar(sal_False);
+-				}
+-			}
+-			WriteNamedExpressions(xSpreadDoc);
+-			aExportDatabaseRanges.WriteDatabaseRanges(xSpreadDoc);
+-			ScXMLExportDataPilot aExportDataPilot(*this);
+-			aExportDataPilot.WriteDataPilots(xSpreadDoc);
+-			WriteConsolidation();
+-			ScXMLExportDDELinks aExportDDELinks(*this);
+-			aExportDDELinks.WriteDDELinks(xSpreadDoc);
+-            IncrementProgressBar(sal_True, 0);
+-			GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference());
++            IncrementProgressBar(sal_False);
++        }
++    }
++    WriteExternalRefCaches();
++    WriteNamedExpressions(xSpreadDoc);
++    aExportDatabaseRanges.WriteDatabaseRanges(xSpreadDoc);
++    ScXMLExportDataPilot aExportDataPilot(*this);
++    aExportDataPilot.WriteDataPilots(xSpreadDoc);
++    WriteConsolidation();
++    ScXMLExportDDELinks aExportDDELinks(*this);
++    aExportDDELinks.WriteDDELinks(xSpreadDoc);
++    IncrementProgressBar(sal_True, 0);
++    GetProgressBarHelper()->SetValue(GetProgressBarHelper()->GetReference());
+ }
+ 
+ void ScXMLExport::_ExportStyles( sal_Bool bUsed )
+@@ -2000,6 +2011,15 @@ void ScXMLExport::_ExportAutoStyles()
+ 
+ 					GetShapeExport()->exportAutoStyles();
+ 					GetFormExport()->exportAutoStyles( );
++
++                    {
++                        // Special table style for the external ref cache tables.
++                        AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sExternalRefTabStyleName);
++                        AddAttribute(XML_NAMESPACE_STYLE, XML_FAMILY, XML_TABLE);
++                        SvXMLElementExport aElemStyle(*this, XML_NAMESPACE_STYLE, XML_STYLE, sal_True, sal_True);
++                        AddAttribute(XML_NAMESPACE_TABLE,  XML_DISPLAY, XML_FALSE);
++                        SvXMLElementExport aElemStyleTabProps(*this, XML_NAMESPACE_STYLE, XML_TABLE_PROPERTIES, sal_True, sal_True);
++                    }
+ 				}
+ 				if (getExportFlags() & EXPORT_MASTERSTYLES)
+ 				{
+@@ -3333,6 +3353,183 @@ void ScXMLExport::WriteNamedExpressions(const com::sun::star::uno::Reference <co
+ 	}
+ }
+ 
++void ScXMLExport::WriteExternalRefCaches()
++{
++    if (!pDoc)
++        return;
++
++    ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++    pRefMgr->resetSrcFileData();
++    sal_uInt16 nCount = pRefMgr->getCachedFileCount();
++    for (sal_uInt16 nFileId = 0; nFileId < nCount; ++nFileId)
++    {
++        const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++        if (!pUrl)
++            continue;
++
++        const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++        if (!pTabNames)
++            continue;
++
++        for (vector<String>::const_iterator itr = pTabNames->begin(), itrEnd = pTabNames->end();
++              itr != itrEnd; ++itr)
++        {
++            ScExternalRefCache::Table* pTable = pRefMgr->getCacheTable(nFileId, *itr, false);
++            if (!pTable)
++                continue;
++
++            OUStringBuffer aBuf;
++            aBuf.append(sal_Unicode('\''));
++            aBuf.append(*pUrl);
++            aBuf.append(sal_Unicode('\''));
++            aBuf.append(sal_Unicode('#'));
++            aBuf.append(*itr);
++            AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, aBuf.makeStringAndClear());
++            AddAttribute(XML_NAMESPACE_TABLE, XML_PRINT, GetXMLToken(XML_FALSE));
++            AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sExternalRefTabStyleName);
++            SvXMLElementExport aElemTable(*this, XML_NAMESPACE_TABLE, XML_TABLE, sal_True, sal_True);
++            {
++                const ScExternalRefManager::SrcFileData* pExtFileData = pRefMgr->getExternalFileData(nFileId);
++                if (pExtFileData)
++                {
++                    String aRelUrl;
++                    if (pExtFileData->maRelativeName.Len())
++                        aRelUrl = pExtFileData->maRelativeName;
++                    else
++                        aRelUrl = GetRelativeReference(pExtFileData->maRelativeName);
++                    AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aRelUrl);
++                    AddAttribute(XML_NAMESPACE_TABLE, XML_TABLE_NAME, *itr);
++                    if (pExtFileData->maFilterName.Len())
++                        AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_NAME, pExtFileData->maFilterName);
++                    if (pExtFileData->maFilterOptions.Len())
++                        AddAttribute(XML_NAMESPACE_TABLE, XML_FILTER_OPTIONS, pExtFileData->maFilterOptions);
++                    AddAttribute(XML_NAMESPACE_TABLE, XML_MODE, XML_COPY_RESULTS_ONLY);
++                }
++                SvXMLElementExport aElemTableSource(*this, XML_NAMESPACE_TABLE, XML_TABLE_SOURCE, sal_True, sal_True);
++            }
++
++            // Write cache content for this table.
++            vector<SCROW> aRows;
++            pTable->getAllRows(aRows);
++            SCROW nLastRow = 0;
++            bool bFirstRow = true;
++            for (vector<SCROW>::const_iterator itrRow = aRows.begin(), itrRowEnd = aRows.end();
++                  itrRow != itrRowEnd; ++itrRow)
++            {
++                SCROW nRow = *itrRow;
++                if (bFirstRow)
++                {
++                    if (nRow > 0)
++                    {   
++                        if (nRow > 1)
++                        {
++                            OUStringBuffer aVal;
++                            aVal.append(nRow);
++                            AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal.makeStringAndClear());
++                        }
++                        SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True);
++                        OUStringBuffer aVal;
++                        aVal.append(static_cast<sal_Int32>(MAXCOLCOUNT));
++                        AddAttribute(XML_NAMESPACE_TABLE,  XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear());
++                        SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True);
++                    }
++                }
++                else
++                {
++                    SCROW nRowGap = nRow - nLastRow;
++                    if (nRowGap > 1)
++                    {
++                        if (nRowGap > 2)
++                        {
++                            OUStringBuffer aVal;
++                            aVal.append(static_cast<sal_Int32>(nRowGap-1));
++                            AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_REPEATED, aVal.makeStringAndClear());
++                        }
++                        SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True);
++                        OUStringBuffer aVal;
++                        aVal.append(static_cast<sal_Int32>(MAXCOLCOUNT));
++                        AddAttribute(XML_NAMESPACE_TABLE,  XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear());
++                        SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True);
++                    }
++                }
++                SvXMLElementExport aElemRow(*this, XML_NAMESPACE_TABLE, XML_TABLE_ROW, sal_True, sal_True);
++
++                vector<SCCOL> aCols;
++                pTable->getAllCols(nRow, aCols);
++                SCCOL nLastCol = 0;
++                bool bFirstCol = true;
++                for (vector<SCCOL>::const_iterator itrCol = aCols.begin(), itrColEnd = aCols.end();
++                      itrCol != itrColEnd; ++itrCol)
++                {
++                    SCCOL nCol = *itrCol;
++                    if (bFirstCol)
++                    {
++                        if (nCol > 0)
++                        {   
++                            if (nCol > 1)
++                            {
++                                OUStringBuffer aVal;
++                                aVal.append(static_cast<sal_Int32>(nCol));
++                                AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear());
++                            }
++                            SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True);
++                        }
++                    }
++                    else
++                    {
++                        SCCOL nColGap = nCol - nLastCol;
++                        if (nColGap > 1)
++                        {
++                            if (nColGap > 2)
++                            {
++                                OUStringBuffer aVal;
++                                aVal.append(static_cast<sal_Int32>(nColGap-1));
++                                AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, aVal.makeStringAndClear());
++                            }
++                            SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True);
++                        }
++                    }
++
++                    // Write out this cell.
++                    ScToken* pToken = pTable->getCell(nRow, nCol).get();
++                    OUString aStrVal;
++                    if (pToken)
++                    {
++                        switch(pToken->GetType())
++                        {
++                            case svDouble:
++                            {
++                                AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT);
++                                OUStringBuffer aVal;
++                                aVal.append(pToken->GetDouble());
++                                aStrVal = aVal.makeStringAndClear();
++                                AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, aStrVal);
++                            }
++                            break;
++                            case svString:
++                            {
++                                AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING);
++                                aStrVal = pToken->GetString();
++                            }
++                            break;
++                            default:
++                                ;
++                        }
++                    }
++                    SvXMLElementExport aElemCell(*this, XML_NAMESPACE_TABLE, XML_TABLE_CELL, sal_True, sal_True);
++                    SvXMLElementExport aElemText(*this, XML_NAMESPACE_TEXT, XML_P, sal_True, sal_False);
++                    Characters(aStrVal);
++
++                    nLastCol = nCol;
++                    bFirstCol = false;
++                }
++                nLastRow = nRow;
++                bFirstRow = false;
++            }
++        }
++    }
++}
++
+ // core implementation
+ void ScXMLExport::WriteConsolidation()
+ {
+diff --git sc/source/filter/xml/xmlexprt.hxx sc/source/filter/xml/xmlexprt.hxx
+index 47171b6..e8477e5 100644
+--- sc/source/filter/xml/xmlexprt.hxx
++++ sc/source/filter/xml/xmlexprt.hxx
+@@ -98,6 +98,7 @@ class ScXMLExport : public SvXMLExport
+ 	ScChangeTrackingExportHelper*	pChangeTrackingExportHelper;
+ 	const rtl::OUString			sLayerID;
+ 	const rtl::OUString			sCaptionShape;
++    rtl::OUString               sExternalRefTabStyleName;
+     rtl::OUString               sAttrName;
+     rtl::OUString               sAttrStyleName;
+     rtl::OUString               sAttrColumnsRepeated;
+@@ -195,6 +196,7 @@ class ScXMLExport : public SvXMLExport
+ 	void WriteTheLabelRanges(const com::sun::star::uno::Reference< com::sun::star::sheet::XSpreadsheetDocument >& xSpreadDoc);
+ 	void WriteLabelRanges( const com::sun::star::uno::Reference< com::sun::star::container::XIndexAccess >& xRangesIAccess, sal_Bool bColumn );
+ 	void WriteNamedExpressions(const com::sun::star::uno::Reference <com::sun::star::sheet::XSpreadsheetDocument>& xSpreadDoc);
++    void WriteExternalRefCaches();
+ 	void WriteConsolidation();	// core implementation
+ 
+ 	void CollectUserDefinedNamespaces(const SfxItemPool* pPool, sal_uInt16 nAttrib);
+diff --git sc/source/filter/xml/xmlexternaltabi.cxx sc/source/filter/xml/xmlexternaltabi.cxx
+new file mode 100644
+index 0000000..e1d0ebd
+--- /dev/null
++++ sc/source/filter/xml/xmlexternaltabi.cxx
+@@ -0,0 +1,343 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: xmlcoli.hxx,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++
++
++// INCLUDE ---------------------------------------------------------------
++
++#include "xmlexternaltabi.hxx"
++#include "xmlimprt.hxx"
++#include "xmltabi.hxx"
++
++#include "token.hxx"
++#include "document.hxx"
++
++#include <xmloff/nmspmap.hxx>
++#include <xmloff/xmlnmspe.hxx>
++#include <xmloff/xmltoken.hxx>
++#include <xmloff/xmluconv.hxx>
++#include <com/sun/star/util/NumberFormat.hpp>
++
++using namespace ::com::sun::star;
++
++using ::rtl::OUString;
++using ::com::sun::star::uno::Reference;
++using ::com::sun::star::xml::sax::XAttributeList;
++
++// ============================================================================
++
++ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext(
++    ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, 
++    const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
++    SvXMLImportContext( rImport, nPrefix, rLName ),
++    mrScImport(rImport), 
++    mrExternalRefInfo(rRefInfo)
++{
++    using namespace ::xmloff::token;
++
++    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
++    for (sal_Int16 i = 0; i < nAttrCount; ++i)
++    {
++        const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i);
++        rtl::OUString aLocalName;
++        sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
++        const rtl::OUString& sValue = xAttrList->getValueByIndex(i);
++        if (nAttrPrefix == XML_NAMESPACE_XLINK)
++        {
++            if (IsXMLToken(aLocalName, XML_HREF))
++                maRelativeUrl = sValue;
++        }
++        else if (nAttrPrefix == XML_NAMESPACE_TABLE)
++        {
++            if (IsXMLToken(aLocalName, XML_TABLE_NAME))
++                maTableName = sValue;
++            else if (IsXMLToken(aLocalName, XML_FILTER_NAME))
++                maFilterName = sValue;
++            else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS))
++                maFilterOptions = sValue;
++        }
++    }
++}
++
++ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext()
++{
++}
++
++SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext(
++    USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ )
++{
++    return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
++}
++
++void ScXMLExternalRefTabSourceContext::EndElement()
++{
++    ScDocument* pDoc = mrScImport.GetDocument();
++    if (!pDoc)
++        return;
++
++    ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++    if (!maRelativeUrl.equals(mrExternalRefInfo.maFileUrl))
++        pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl);
++    pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions);
++}
++
++// ============================================================================
++
++ScXMLExternalRefRowContext::ScXMLExternalRefRowContext(
++    ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, 
++    const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
++    SvXMLImportContext( rImport, nPrefix, rLName ),
++    mrScImport(rImport), 
++    mrExternalRefInfo(rRefInfo),
++    mnRepeatRowCount(1)
++{
++    mrExternalRefInfo.mnCol = 0;
++
++    sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0);
++    const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap();
++    for( sal_Int16 i=0; i < nAttrCount; ++i )
++    {
++        const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i);
++        rtl::OUString aLocalName;
++        sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
++        const rtl::OUString& sValue = xAttrList->getValueByIndex(i);
++
++        switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName))
++        {
++            case XML_TOK_TABLE_ROW_ATTR_REPEATED:
++            {
++                mnRepeatRowCount = std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
++            }
++            break;
++        }
++    }
++}
++
++ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext()
++{
++}
++
++SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext(
++    USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
++{
++    const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap();
++    sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
++    if (nToken == XML_TOK_TABLE_ROW_CELL)
++        return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo);
++
++    return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
++}
++
++void ScXMLExternalRefRowContext::EndElement()
++{
++    ScExternalRefCache::Table* pTab = mrExternalRefInfo.mpCacheTable;
++
++    for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i)
++    {
++        for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j)
++        {
++            ScExternalRefCache::TokenRef pToken = pTab->getCell(
++                static_cast<SCROW>(mrExternalRefInfo.mnRow), static_cast<SCCOL>(j));
++
++            if (pToken.get())
++            {
++                pTab->setCell(static_cast<SCROW>(
++                    mrExternalRefInfo.mnRow+i), static_cast<SCCOL>(j), pToken);
++            }
++        }
++    }
++    mrExternalRefInfo.mnRow += mnRepeatRowCount;
++}
++
++// ============================================================================
++
++ScXMLExternalRefCellContext::ScXMLExternalRefCellContext(
++    ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, 
++    const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
++    SvXMLImportContext( rImport, nPrefix, rLName ),
++    mrScImport(rImport), 
++    mrExternalRefInfo(rRefInfo),
++    mfCellValue(0.0),
++    mnRepeatCount(1),
++    mnCellType(::com::sun::star::util::NumberFormat::UNDEFINED),
++    mbIsNumeric(false),
++    mbIsEmpty(true)
++{
++    using namespace ::xmloff::token;
++
++    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
++    const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap();
++    for (sal_Int16 i = 0; i < nAttrCount; ++i)
++    {
++        OUString aLocalName;
++        sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(
++            xAttrList->getNameByIndex(i), &aLocalName);
++
++        const rtl::OUString& sValue = xAttrList->getValueByIndex(i);
++        sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName);
++
++        switch (nToken)
++        {
++            case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED:
++            {    
++                mnRepeatCount = ::std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
++            {
++                mnCellType = mrScImport.GetCellType(sValue);
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
++            {
++                if (sValue.getLength())
++                {
++                    mrScImport.GetMM100UnitConverter().convertDouble(mfCellValue, sValue);
++                    mbIsNumeric = true;
++                    mbIsEmpty = false;
++                }
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE:
++            {
++                if (sValue.getLength() && mrScImport.SetNullDateOnUnitConverter())
++                {
++                    mrScImport.GetMM100UnitConverter().convertDateTime(mfCellValue, sValue);
++                    mbIsNumeric = true;
++                    mbIsEmpty = false;
++                }
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE:
++            {
++                if (sValue.getLength())
++                {
++                    mrScImport.GetMM100UnitConverter().convertTime(mfCellValue, sValue);
++                    mbIsNumeric = true;
++                    mbIsEmpty = false;
++                }
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE:
++            {
++                if (sValue.getLength())
++                {
++                    maCellString = sValue;
++                    mbIsNumeric = false;
++                    mbIsEmpty = false;
++                }
++            }
++            break;
++            case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE:
++            {
++                if (sValue.getLength())
++                {
++                    mfCellValue = IsXMLToken(sValue, XML_TRUE) ? 1.0 : 0.0;
++                    mbIsNumeric = true;
++                    mbIsEmpty = false;
++                }
++            }
++            break;
++            default:
++                ;
++        }
++    }
++}
++
++ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext()
++{
++}
++
++SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext(
++    USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
++{
++    const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap();
++    sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
++    if (nToken == XML_TOK_TABLE_ROW_CELL_P)
++        return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, maCellString);
++
++    return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
++}
++
++void ScXMLExternalRefCellContext::EndElement()
++{
++    if (maCellString.getLength())
++        mbIsEmpty = false;
++
++    for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol)
++    {
++        if (mbIsEmpty)
++            continue;
++
++        ScExternalRefCache::TokenRef aToken;
++        if (mbIsNumeric)
++            aToken.reset(new ScDoubleToken(mfCellValue));
++        else
++            aToken.reset(new ScStringToken(maCellString));
++
++        mrExternalRefInfo.mpCacheTable->setCell(
++            static_cast<SCROW>(mrExternalRefInfo.mnRow), 
++            static_cast<SCCOL>(mrExternalRefInfo.mnCol), 
++            aToken);
++    }
++}
++
++// ============================================================================
++
++ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext(
++    ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, 
++    const Reference<XAttributeList>& /*xAttrList*/, OUString& rCellString ) :
++    SvXMLImportContext( rImport, nPrefix, rLName ),
++    mrScImport(rImport), 
++    mrCellString(rCellString)
++{
++}
++
++ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext()
++{
++}
++
++SvXMLImportContext* ScXMLExternalRefCellTextContext::CreateChildContext(
++    USHORT nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ )
++{
++    return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
++}
++
++void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar)
++{
++    mrCellString = rChar;
++}
++
++void ScXMLExternalRefCellTextContext::EndElement()
++{
++}
+diff --git sc/source/filter/xml/xmlexternaltabi.hxx sc/source/filter/xml/xmlexternaltabi.hxx
+new file mode 100644
+index 0000000..6f26789
+--- /dev/null
++++ sc/source/filter/xml/xmlexternaltabi.hxx
+@@ -0,0 +1,149 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: xmlcoli.hxx,v $
++ * $Revision: 1.9 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_XMLEXTERNALTABI_HXX
++#define SC_XMLEXTERNALTABI_HXX
++
++#include <xmloff/xmlictxt.hxx>
++
++class ScXMLImport;
++struct ScXMLExternalTabData;
++
++class ScXMLExternalRefTabSourceContext : public SvXMLImportContext
++{
++public:
++    ScXMLExternalRefTabSourceContext( ScXMLImport& rImport, USHORT nPrefix,
++                        const ::rtl::OUString& rLName,
++                        const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++                        ScXMLExternalTabData& rRefInfo );
++
++    virtual ~ScXMLExternalRefTabSourceContext();
++
++    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
++                                     const ::rtl::OUString& rLocalName,
++                                     const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
++
++    virtual void EndElement();
++private:
++    ScXMLImport&            mrScImport;
++    ScXMLExternalTabData&   mrExternalRefInfo;
++
++    ::rtl::OUString         maRelativeUrl;
++    ::rtl::OUString         maTableName;
++    ::rtl::OUString         maFilterName;
++    ::rtl::OUString         maFilterOptions;
++};
++
++// ============================================================================
++
++class ScXMLExternalRefRowContext : public SvXMLImportContext
++{
++public:
++    ScXMLExternalRefRowContext( ScXMLImport& rImport, USHORT nPrefix,
++                        const ::rtl::OUString& rLName,
++                        const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++                        ScXMLExternalTabData& rRefInfo );
++
++    virtual ~ScXMLExternalRefRowContext();
++
++    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
++                                     const ::rtl::OUString& rLocalName,
++                                     const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
++
++    virtual void EndElement();
++private:
++    ScXMLImport&            mrScImport;
++    ScXMLExternalTabData&   mrExternalRefInfo;
++    sal_Int32               mnRepeatRowCount;
++};
++
++// ============================================================================
++
++class ScXMLExternalRefCellContext : public SvXMLImportContext
++{
++public:
++    ScXMLExternalRefCellContext( ScXMLImport& rImport, USHORT nPrefix,
++                        const ::rtl::OUString& rLName,
++                        const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++                        ScXMLExternalTabData& rRefInfo );
++
++    virtual ~ScXMLExternalRefCellContext();
++
++    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
++                                     const ::rtl::OUString& rLocalName,
++                                     const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
++
++    virtual void EndElement();
++
++private:
++    ScXMLImport&            mrScImport;
++    ScXMLExternalTabData&   mrExternalRefInfo;
++    ::rtl::OUString         maCellString;
++    double                  mfCellValue;
++    sal_Int32               mnRepeatCount;
++    sal_Int16               mnCellType;
++    bool                    mbIsNumeric;
++    bool                    mbIsEmpty;
++};
++
++// ============================================================================
++
++class ScXMLExternalRefCellTextContext : public SvXMLImportContext
++{
++public:
++    ScXMLExternalRefCellTextContext( ScXMLImport& rImport, USHORT nPrefix,
++                        const ::rtl::OUString& rLName,
++                        const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++                        ::rtl::OUString& rCellString );
++
++    virtual ~ScXMLExternalRefCellTextContext();
++
++    virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
++                                     const ::rtl::OUString& rLocalName,
++                                     const ::com::sun::star::uno::Reference<
++                                        ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
++
++    virtual void Characters(const ::rtl::OUString& rChar);
++
++    virtual void EndElement();
++
++private:
++    ScXMLImport&            mrScImport;
++    ::rtl::OUString&        mrCellString;
++};
++
++#endif
+diff --git sc/source/filter/xml/xmlimprt.cxx sc/source/filter/xml/xmlimprt.cxx
+index 47b26b9..eb74c99 100644
+--- sc/source/filter/xml/xmlimprt.cxx
++++ sc/source/filter/xml/xmlimprt.cxx
+@@ -104,6 +104,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace ::xmloff::token;
++using ::rtl::OUString;
+ 
+ OUString SAL_CALL ScXMLImport_getImplementationName() throw()
+ {
+@@ -417,22 +418,22 @@ static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTokenMap[] =
+ 
+ static __FAR_DATA SvXMLTokenMapEntry aTableRowCellAttrTokenMap[] =
+ {
+-	{ XML_NAMESPACE_TABLE, XML_STYLE_NAME,						XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME				},
+-	{ XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME, 		XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME	},
+-	{ XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED,  			XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS			},
+-	{ XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED,			XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS			},
+-	{ XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_COLUMNS_SPANNED,   XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS		},
+-	{ XML_NAMESPACE_TABLE, XML_NUMBER_MATRIX_ROWS_SPANNED,		XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS		},
+-	{ XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,		    XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED				},
+-	{ XML_NAMESPACE_TABLE, XML_VALUE_TYPE,						XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE				},
+-	{ XML_NAMESPACE_TABLE, XML_VALUE,							XML_TOK_TABLE_ROW_CELL_ATTR_VALUE					},
+-	{ XML_NAMESPACE_TABLE, XML_DATE_VALUE,						XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE				},
+-	{ XML_NAMESPACE_TABLE, XML_TIME_VALUE,						XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE				},
+-	{ XML_NAMESPACE_TABLE, XML_STRING_VALUE,					XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE			},
+-	{ XML_NAMESPACE_TABLE, XML_BOOLEAN_VALUE,					XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE			},
+-	{ XML_NAMESPACE_TABLE, XML_FORMULA, 						XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA					},
+-	{ XML_NAMESPACE_TABLE, XML_CURRENCY,						XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY				},
+-	XML_TOKEN_MAP_END
++    { XML_NAMESPACE_TABLE,  XML_STYLE_NAME,                     XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME              },
++    { XML_NAMESPACE_TABLE,  XML_CONTENT_VALIDATION_NAME,        XML_TOK_TABLE_ROW_CELL_ATTR_CONTENT_VALIDATION_NAME },
++    { XML_NAMESPACE_TABLE,  XML_NUMBER_ROWS_SPANNED,            XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_ROWS            },
++    { XML_NAMESPACE_TABLE,  XML_NUMBER_COLUMNS_SPANNED,         XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_COLS            },
++    { XML_NAMESPACE_TABLE,  XML_NUMBER_MATRIX_COLUMNS_SPANNED,  XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_COLS     },
++    { XML_NAMESPACE_TABLE,  XML_NUMBER_MATRIX_ROWS_SPANNED,     XML_TOK_TABLE_ROW_CELL_ATTR_SPANNED_MATRIX_ROWS     },
++    { XML_NAMESPACE_TABLE,  XML_NUMBER_COLUMNS_REPEATED,        XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED                },
++    { XML_NAMESPACE_OFFICE, XML_VALUE_TYPE,                     XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE              },
++    { XML_NAMESPACE_OFFICE, XML_VALUE,                          XML_TOK_TABLE_ROW_CELL_ATTR_VALUE                   },
++    { XML_NAMESPACE_OFFICE, XML_DATE_VALUE,                     XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE              },
++    { XML_NAMESPACE_OFFICE, XML_TIME_VALUE,                     XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE              },
++    { XML_NAMESPACE_OFFICE, XML_STRING_VALUE,                   XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE            },
++    { XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE,                  XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE           },
++    { XML_NAMESPACE_TABLE,  XML_FORMULA,                        XML_TOK_TABLE_ROW_CELL_ATTR_FORMULA                 },
++    { XML_NAMESPACE_OFFICE, XML_CURRENCY,                       XML_TOK_TABLE_ROW_CELL_ATTR_CURRENCY                },
++    XML_TOKEN_MAP_END
+ };
+ 
+ static __FAR_DATA SvXMLTokenMapEntry aTableAnnotationAttrTokenMap[] =
+@@ -1561,6 +1562,25 @@ ScXMLImport::ScXMLImport(
+         GetXMLToken( XML_NP_PRESENTATION ),
+         GetXMLToken( XML_N_PRESENTATION ),
+         XML_NAMESPACE_PRESENTATION );
++
++    // initialize cell type map.
++    const struct { XMLTokenEnum  _token; sal_Int16 _type; } aCellTypePairs[] = 
++    {
++        { XML_FLOAT,        util::NumberFormat::NUMBER },
++        { XML_STRING,       util::NumberFormat::TEXT },
++        { XML_TIME,         util::NumberFormat::TIME },
++        { XML_DATE,         util::NumberFormat::DATETIME },
++        { XML_PERCENTAGE,   util::NumberFormat::PERCENT },
++        { XML_CURRENCY,     util::NumberFormat::CURRENCY },
++        { XML_BOOLEAN,      util::NumberFormat::LOGICAL }
++    };
++    size_t n = sizeof(aCellTypePairs)/sizeof(aCellTypePairs[0]);
++    for (size_t i = 0; i < n; ++i)
++    {
++        aCellTypeMap.insert(
++            CellTypeMap::value_type(
++                GetXMLToken(aCellTypePairs[i]._token), aCellTypePairs[i]._type));
++    }
+ }
+ 
+ ScXMLImport::~ScXMLImport() throw()
+@@ -1777,6 +1797,15 @@ void ScXMLImport::SetStatistics(
+ 	}
+ }
+ 
++sal_Int16 ScXMLImport::GetCellType(const OUString& rStrValue) const
++{
++    CellTypeMap::const_iterator itr = aCellTypeMap.find(rStrValue);
++    if (itr != aCellTypeMap.end())
++        return itr->second;
++
++    return util::NumberFormat::UNDEFINED;
++}
++
+ XMLShapeImportHelper* ScXMLImport::CreateShapeImport()
+ {
+ 	/*UniReference < XMLPropertySetMapper > xShapeStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScShapeStylesProperties, xScPropHdlFactory);
+diff --git sc/source/filter/xml/xmlimprt.hxx sc/source/filter/xml/xmlimprt.hxx
+index e4fd8a0..cace08e 100644
+--- sc/source/filter/xml/xmlimprt.hxx
++++ sc/source/filter/xml/xmlimprt.hxx
+@@ -40,7 +40,6 @@
+ #include <com/sun/star/frame/XModel.hpp>
+ #include <tools/time.hxx>
+ #include <com/sun/star/util/DateTime.hpp>
+-#include <vector>
+ #include "xmlsubti.hxx"
+ #include "global.hxx"
+ #include "grammar.hxx"
+@@ -55,12 +54,13 @@
+ #include <com/sun/star/util/XNumberFormatTypes.hpp>
+ #include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+ 
++#include <vector>
++#include <hash_map>
++
+ class ScRangeList;
+ class ScMyStyleNumberFormats;
+ class XMLNumberFormatAttributesExportHelper;
+ 
+-using namespace rtl;
+-
+ enum ScXMLDocTokens
+ {
+ 	XML_TOK_DOC_FONTDECLS,
+@@ -643,6 +643,9 @@ class ScMyStylesImportHelper;
+ 
+ class ScXMLImport: public SvXMLImport
+ {
++	typedef ::std::hash_map< ::rtl::OUString, sal_Int16, ::rtl::OUStringHash >	CellTypeMap;
++	CellTypeMap				aCellTypeMap;
++
+ 	ScDocument*				pDoc;
+ 	ScXMLChangeTrackingImportHelper*	pChangeTrackingImportHelper;
+ 	ScMyViewContextList					aViewContextList;
+@@ -810,6 +813,8 @@ public:
+ 
+     sal_Bool IsLatinDefaultStyle() const  { return bLatinDefaultStyle; }
+ 
++	sal_Int16 GetCellType(const ::rtl::OUString& rStrValue) const;
++
+ //	SvI18NMap& GetI18NMap() { return *pI18NMap; }
+ 
+ //	inline const SvXMLImportItemMapper& GetParaItemMapper() const;
+diff --git sc/source/filter/xml/xmlsceni.cxx sc/source/filter/xml/xmlsceni.cxx
+index cfe859d..f4d6c89 100644
+--- sc/source/filter/xml/xmlsceni.cxx
++++ sc/source/filter/xml/xmlsceni.cxx
+@@ -50,6 +50,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace xmloff::token;
++using ::rtl::OUString;
+ 
+ //------------------------------------------------------------------
+ 
+diff --git sc/source/filter/xml/xmlstyle.cxx sc/source/filter/xml/xmlstyle.cxx
+index 7aec632..863e82c 100644
+--- sc/source/filter/xml/xmlstyle.cxx
++++ sc/source/filter/xml/xmlstyle.cxx
+@@ -65,6 +65,7 @@
+ 
+ using namespace com::sun::star;
+ using namespace ::xmloff::token;
++using ::rtl::OUString;
+ 
+ #define MAP(name,prefix,token,type,context)  { name, sizeof(name)-1, prefix, token, type, context, SvtSaveOptions::ODFVER_010 }
+ #define MAP_END()	{ NULL, 0, 0, XML_TOKEN_INVALID, 0, 0, SvtSaveOptions::ODFVER_010 }
+diff --git sc/source/filter/xml/xmlstyle.hxx sc/source/filter/xml/xmlstyle.hxx
+index 4d51084..ee9a2ea 100644
+--- sc/source/filter/xml/xmlstyle.hxx
++++ sc/source/filter/xml/xmlstyle.hxx
+@@ -40,8 +40,6 @@
+ #include <xmloff/xmlexppr.hxx>
+ #include <xmloff/contextid.hxx>
+ 
+-using namespace rtl;
+-
+ extern const XMLPropertyMapEntry aXMLScCellStylesProperties[];
+ extern const XMLPropertyMapEntry aXMLScColumnStylesProperties[];
+ extern const XMLPropertyMapEntry aXMLScRowStylesProperties[];
+diff --git sc/source/filter/xml/xmltabi.cxx sc/source/filter/xml/xmltabi.cxx
+index 4a0f83e..264901d 100644
+--- sc/source/filter/xml/xmltabi.cxx
++++ sc/source/filter/xml/xmltabi.cxx
+@@ -40,6 +40,7 @@
+ #include "xmlrowi.hxx"
+ #include "xmlcoli.hxx"
+ #include "xmlsceni.hxx"
++#include "xmlexternaltabi.hxx"
+ #include "document.hxx"
+ #include "docuno.hxx"
+ #include "olinetab.hxx"
+@@ -48,6 +49,7 @@
+ #include "XMLTableSourceContext.hxx"
+ #include "XMLStylesImportHelper.hxx"
+ #include "rangeutl.hxx"
++#include "externalrefmgr.hxx"
+ 
+ #include <xmloff/xmltkmap.hxx>
+ #include <xmloff/nmspmap.hxx>
+@@ -63,6 +65,77 @@
+ using namespace com::sun::star;
+ using namespace xmloff::token;
+ 
++/** 
++ * Determine whether this table is an external reference cache from its 
++ * name.  There is currently no way of determining whether a table is a
++ * regular table or an external reference cache other than examining the 
++ * name itself.  We should probably introduce a new boolean value for 
++ * table:table element and use it instead of doing this, to make it more 
++ * reliable and future-proof. 
++ *
++ * @param rName 
++ * 
++ * @return 
++ */
++static bool lcl_isExternalRefCache(const rtl::OUString& rName, rtl::OUString& rUrl, rtl::OUString& rExtTabName)
++{
++    // 'file:///path/to/file.ods'#MySheet
++    // 'file:///path/to/file.ods'#MySheet with space
++    // 'file:///path/to/file's.ods'#Sheet (Notice the quote in the file name.
++    //  That's allowed.)
++
++    static const sal_Unicode aPrefix[] = {
++        '\'', 'f', 'i', 'l', 'e', ':', '/', '/'
++    };
++
++    rtl::OUStringBuffer aUrlBuf, aTabNameBuf;
++    aUrlBuf.appendAscii("file://");
++    sal_Int32 n = rName.getLength();
++    const sal_Unicode* p = rName.getStr();
++
++    bool bInUrl = true;
++    sal_Unicode cPrev = 0;
++    for (sal_Int32 i = 0; i < n; ++i)
++    {
++        const sal_Unicode c = p[i];
++        if (i <= 7)
++        {
++            if (c != aPrefix[i])
++                return false;
++        }
++        else if (c == '#')
++        {
++            if (cPrev != '\'')
++                return false;
++
++            rUrl = aUrlBuf.makeStringAndClear();
++            rUrl = rUrl.copy(0, rUrl.getLength()-1); // remove the trailing single-quote.
++            bInUrl = false;
++        }
++        else if (bInUrl)
++            aUrlBuf.append(c);
++        else
++            aTabNameBuf.append(c);
++
++        cPrev = c;
++    }
++
++    if (bInUrl)
++        return false;
++
++    if (aTabNameBuf.getLength() == 0)
++        return false;
++
++    rExtTabName = aTabNameBuf.makeStringAndClear();
++
++    return true;
++}
++
++ScXMLExternalTabData::ScXMLExternalTabData() :
++    mpCacheTable(NULL), mnRow(0), mnCol(0), mnFileId(0)
++{
++}
++
+ //------------------------------------------------------------------
+ 
+ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
+@@ -73,6 +146,7 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
+ 									  const sal_Bool bTempIsSubTable,
+ 									  const sal_Int32 nSpannedCols) :
+ 	SvXMLImportContext( rImport, nPrfx, rLName ),
++    pExternalRefInfo(NULL),
+ 	bStartFormPage(sal_False),
+     bPrintEntireSheet(sal_True)
+ {
+@@ -117,7 +191,26 @@ ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
+                     break;
+ 			}
+ 		}
+-		GetScImport().GetTables().NewSheet(sName, sStyleName, bProtection, sPassword);
++
++        rtl::OUString aExtUrl, aExtTabName;
++        if (lcl_isExternalRefCache(sName, aExtUrl, aExtTabName))
++        {
++            // This is an external ref cache table.
++            pExternalRefInfo.reset(new ScXMLExternalTabData);
++            pExternalRefInfo->maFileUrl = aExtUrl;
++            ScDocument* pDoc = GetScImport().GetDocument();
++            if (pDoc)
++            {
++                ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
++                pExternalRefInfo->mnFileId = pRefMgr->getExternalFileId(aExtUrl);
++                pExternalRefInfo->mpCacheTable = pRefMgr->getCacheTable(pExternalRefInfo->mnFileId, aExtTabName, true);
++            }
++        }
++        else
++        {
++            // This is a regular table.
++            GetScImport().GetTables().NewSheet(sName, sStyleName, bProtection, sPassword);
++        }
+ 	}
+ 	else
+ 	{
+@@ -134,10 +227,30 @@ SvXMLImportContext *ScXMLTableContext::CreateChildContext( USHORT nPrefix,
+ 											const ::com::sun::star::uno::Reference<
+ 									  	::com::sun::star::xml::sax::XAttributeList>& xAttrList )
+ {
++	const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap());
++    sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLName);
++    if (pExternalRefInfo.get())
++    {
++        // We only care about the table-row and table-source elements for 
++        // external cache data.
++        switch (nToken)
++        {
++            case XML_TOK_TABLE_ROW:
++                return new ScXMLExternalRefRowContext(
++                    GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo);
++            case XML_TOK_TABLE_SOURCE:
++                return new ScXMLExternalRefTabSourceContext(
++                    GetScImport(), nPrefix, rLName, xAttrList, *pExternalRefInfo);
++            default:
++                ;
++        }
++
++        return new SvXMLImportContext(GetImport(), nPrefix, rLName);
++    }
++
+ 	SvXMLImportContext *pContext(0);
+ 
+-	const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap());
+-	switch( rTokenMap.Get( nPrefix, rLName ) )
++	switch (nToken)
+ 	{
+ 	case XML_TOK_TABLE_COL_GROUP:
+ 		pContext = new ScXMLTableColsContext( GetScImport(), nPrefix,
+@@ -195,6 +308,8 @@ SvXMLImportContext *ScXMLTableContext::CreateChildContext( USHORT nPrefix,
+ 			pContext = GetScImport().GetFormImport()->createOfficeFormsContext( GetScImport(), nPrefix, rLName );
+ 		}
+ 		break;
++    default:
++        ;
+ 	}
+ 
+ 	if( !pContext )
+diff --git sc/source/filter/xml/xmltabi.hxx sc/source/filter/xml/xmltabi.hxx
+index 687cff8..e2960c2 100644
+--- sc/source/filter/xml/xmltabi.hxx
++++ sc/source/filter/xml/xmltabi.hxx
+@@ -30,13 +30,28 @@
+ #ifndef SC_XMLTABI_HXX
+ #define SC_XMLTABI_HXX
+ 
++#include "externalrefmgr.hxx"
++
+ #include <xmloff/xmlictxt.hxx>
++#include <memory>
+ 
+ class ScXMLImport;
+ 
++struct ScXMLExternalTabData
++{
++    String maFileUrl;
++    ScExternalRefCache::Table* mpCacheTable;
++    sal_Int32 mnRow;
++    sal_Int32 mnCol;
++    sal_uInt16 mnFileId;
++
++    ScXMLExternalTabData();
++};
++
+ class ScXMLTableContext : public SvXMLImportContext
+ {
+ 	rtl::OUString	sPrintRanges;
++    ::std::auto_ptr<ScXMLExternalTabData> pExternalRefInfo;
+ 	sal_Bool		bStartFormPage;
+     sal_Bool        bPrintEntireSheet;
+ 
+diff --git sc/source/filter/xml/xmlwrap.cxx sc/source/filter/xml/xmlwrap.cxx
+index 851d338..035793b 100644
+--- sc/source/filter/xml/xmlwrap.cxx
++++ sc/source/filter/xml/xmlwrap.cxx
+@@ -85,6 +85,7 @@
+ #define MAP_LEN(x) x, sizeof(x) - 1
+ 
+ using namespace com::sun::star;
++using ::rtl::OUString;
+ 
+ // -----------------------------------------------------------------------
+ 
+diff --git sc/source/ui/docshell/docsh4.cxx sc/source/ui/docshell/docsh4.cxx
+index bc5975d..6701d1c 100644
+--- sc/source/ui/docshell/docsh4.cxx
++++ sc/source/ui/docshell/docsh4.cxx
+@@ -123,6 +123,7 @@ using namespace ::com::sun::star;
+ #include <com/sun/star/document/UpdateDocMode.hpp>
+ #include "scresid.hxx" //add by CHINA001
+ #include "scabstdlg.hxx" //CHINA001
++#include "externalrefmgr.hxx"
+ 
+ #include "sharedocdlg.hxx"
+ 
+@@ -540,6 +541,7 @@ void ScDocShell::Execute( SfxRequest& rReq )
+ 				if (nDlgRet == RET_YES || nSet==LM_ALWAYS)
+ 				{
+ 					ReloadTabLinks();
++                    aDocument.UpdateExternalRefLinks();
+ 					aDocument.UpdateDdeLinks();
+ 					aDocument.UpdateAreaLinks();
+ 
+diff --git sc/source/ui/docshell/externalrefmgr.cxx sc/source/ui/docshell/externalrefmgr.cxx
+new file mode 100644
+index 0000000..25266aa
+--- /dev/null
++++ sc/source/ui/docshell/externalrefmgr.cxx
+@@ -0,0 +1,1328 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: document.hxx,v $
++ * $Revision: 1.112 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++
++
++// INCLUDE ---------------------------------------------------------------
++
++#include "externalrefmgr.hxx"
++#include "document.hxx"
++#include "token.hxx"
++#include "tokenarray.hxx"
++#include "address.hxx"
++#include "tablink.hxx"
++#include "docsh.hxx"
++#include "scextopt.hxx"
++#include "rangenam.hxx"
++#include "cell.hxx"
++#include "viewdata.hxx"
++#include "tabvwsh.hxx"
++#include "sc.hrc"
++
++#include "sfx2/app.hxx"
++#include "sfx2/docfilt.hxx"
++#include "sfx2/docfile.hxx"
++#include "sfx2/fcontnr.hxx"
++#include "sfx2/sfxsids.hrc"
++#include "sfx2/objsh.hxx"
++#include "svtools/broadcast.hxx"
++#include "svtools/smplhint.hxx"
++#include "svtools/itemset.hxx"
++#include "svtools/stritem.hxx"
++#include "svtools/urihelper.hxx"
++#include "svx/linkmgr.hxx"
++#include "tools/urlobj.hxx"
++#include "unotools/ucbhelper.hxx"
++
++#include <memory>
++#include <algorithm>
++
++using ::std::auto_ptr;
++using ::com::sun::star::uno::Any;
++using ::rtl::OUString;
++using ::std::vector;
++using ::std::find;
++using ::std::distance;
++
++#define SRCDOC_LIFE_SPAN     6000       // 1 minute (in 100th of a sec)
++#define SRCDOC_SCAN_INTERVAL 1000*5     // every 5 seconds (in msec)
++
++// ============================================================================
++
++ScExternalRefCache::Table::Table()
++{
++}
++
++ScExternalRefCache::Table::~Table()
++{
++}
++
++void ScExternalRefCache::Table::setCell(SCROW nRow, SCCOL nCol, TokenRef pToken)
++{
++    using ::std::pair;
++    RowsDataType::iterator itrRow = maRows.find(nRow);
++    if (itrRow == maRows.end())
++    {
++        // This row does not exist yet.
++        pair<RowsDataType::iterator, bool> res = maRows.insert(
++            RowsDataType::value_type(nRow, RowDataType()));
++
++        if (!res.second)
++            return;
++
++        itrRow = res.first;
++    }
++
++    // Insert this token into the specified column location.  I don't need to 
++    // check for existing data.  Just overwrite it.
++    RowDataType& rRow = itrRow->second;
++    rRow.insert(RowDataType::value_type(nCol, pToken));
++}
++
++ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCROW nRow, SCCOL nCol) const
++{
++    RowsDataType::const_iterator itrTable = maRows.find(nRow);
++    if (itrTable == maRows.end())
++    {
++        // this table doesn't have the specified row.
++        return TokenRef();
++    }
++
++    const RowDataType& rRowData = itrTable->second;
++    RowDataType::const_iterator itrRow = rRowData.find(nCol);
++    if (itrRow == rRowData.end())
++    {
++        // this row doesn't have the specified column.
++        return TokenRef();
++    }
++
++    return itrRow->second;
++}
++
++void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const
++{
++    vector<SCROW> aRows;
++    aRows.reserve(maRows.size());
++    RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
++    for (; itr != itrEnd; ++itr)
++        aRows.push_back(itr->first);
++
++    // hash map is not ordered, so we need to explicitly sort it.
++    ::std::sort(aRows.begin(), aRows.end());
++    rRows.swap(aRows);
++}
++
++void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const
++{
++    RowsDataType::const_iterator itrRow = maRows.find(nRow);
++    if (itrRow == maRows.end())
++        // this table doesn't have the specified row.
++        return;
++
++    const RowDataType& rRowData = itrRow->second;
++    vector<SCCOL> aCols;
++    aCols.reserve(rRowData.size());
++    RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
++    for (; itrCol != itrColEnd; ++itrCol)
++        aCols.push_back(itrCol->first);
++
++    // hash map is not ordered, so we need to explicitly sort it.
++    ::std::sort(aCols.begin(), aCols.end());
++    rCols.swap(aCols);
++}
++
++// ----------------------------------------------------------------------------
++
++ScExternalRefCache::ScExternalRefCache()
++{
++}
++ScExternalRefCache::~ScExternalRefCache()
++{
++}
++
++ScToken* ScExternalRefCache::getCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol)
++{
++    DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++    {
++        // specified document is not cached.
++        return NULL;
++    }
++
++    const DocItem& rDoc = itrDoc->second;
++    TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(rTabName);
++    if (itrTabId == rDoc.maTableNameIndex.end())
++    {
++        // the specified table is not in cache.
++        return NULL;
++    }
++
++    const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
++    if (!pTableData.get())
++    {
++        // the table data is not instantiated yet.
++        return NULL;
++    }
++    return pTableData->getCell(nRow, nCol).get();
++}
++
++ScTokenArray* ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
++{
++    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++        // specified document is not cached.
++        return NULL;
++
++    DocItem& rDoc = itrDoc->second;
++    RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange);
++    if (itrRange != rDoc.maRangeArrays.end())
++    {
++        return itrRange->second.get();
++    }
++
++    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;
++
++    TokenArrayRef pArray(new ScTokenArray);
++    bool bFirstTab = true;
++    for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
++    {
++        TableTypeRef pTab = rDoc.maTables[nTab];
++        if (!pTab.get())
++            return NULL;
++
++        ScMatrixRef xMat = new ScMatrix(
++            static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
++
++        for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
++        {
++            for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
++            {
++                ScToken* pToken = pTab->getCell(nRow, nCol).get();
++                if (!pToken)
++                    return NULL;
++
++                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;
++    }
++    rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
++    return pArray.get();
++}
++
++ScTokenArray* ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    RangeNameMap& rMap = pDoc->maRangeNames;
++    RangeNameMap::const_iterator itr = rMap.find(rName);
++    if (itr == rMap.end())
++        return NULL;
++
++    return itr->second.get();
++}
++
++void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return;
++
++    RangeNameMap& rMap = pDoc->maRangeNames;
++    rMap.insert(RangeNameMap::value_type(rName, pArray));
++}
++
++void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, TokenRef pToken)
++{
++    if (!isDocInitialized(nFileId))
++        return;
++
++    using ::std::pair;
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem)
++        return;
++
++    DocItem& rDoc = *pDocItem;
++    
++    // See if the table by this name already exists.
++    TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(rTabName);
++    if (itrTabName == rDoc.maTableNameIndex.end())
++        // Table not found.  Maybe the table name or the file id is wrong ???
++        return;
++
++    TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
++    if (!pTableData.get())
++        pTableData.reset(new Table);
++
++    pTableData->setCell(nRow, nCol, pToken);
++}
++
++void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
++                                          TokenArrayRef pArray)
++{
++    using ::std::pair;
++    if (rData.empty() || !isDocInitialized(nFileId))
++        // nothing to cache
++        return;
++
++    // First, get the document item for the given file ID.
++    DocItem* pDocItem = getDocItem(nFileId);
++    if (!pDocItem)
++        return;
++
++    DocItem& rDoc = *pDocItem;
++
++    // Now, find the table position of the first table to cache.
++    const String& rFirstTabName = rData.front().maTableName;
++    TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(rFirstTabName);
++    if (itrTabName == rDoc.maTableNameIndex.end())
++    {
++        // table index not found.
++        return;
++    }
++
++    size_t nTab1 = itrTabName->second;
++    SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
++    SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
++    vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
++    for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
++    {
++        size_t i = nTab1 + ::std::distance(itrDataBeg, itrData);
++        TableTypeRef& pTabData = rDoc.maTables[i];
++        if (!pTabData.get())
++            pTabData.reset(new Table);
++
++        for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
++        {
++            for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
++            {
++                SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
++                TokenRef pToken;
++                const ScMatrixRef& pMat = itrData->mpRangeData;
++                if (pMat->IsValue(nC, nR))
++                    pToken.reset(new ScDoubleToken(pMat->GetDouble(nC, nR)));
++                else if (pMat->IsString(nC, nR))
++                    pToken.reset(new ScStringToken(pMat->GetString(nC, nR)));
++                else
++                    pToken.reset(new ScEmptyCellToken(false, false));
++
++                pTabData->setCell(nRow, nCol, pToken);
++            }
++        }
++    }
++
++    rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
++}
++
++bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return false;
++
++    return pDoc->mbInitFromSource;
++}
++
++static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
++{
++    ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
++    if (itr == rMap.end())
++        return false;
++
++    rIndex = itr->second;
++    return true;
++}
++
++void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return;
++
++    size_t n = rTabNames.size();
++
++    // table name list - the list must include all table names in the source 
++    // document and only to be populated when loading the source document, not
++    // when loading cached data from, say, Excel XCT/CRN records.
++    pDoc->maTableNames.assign(rTabNames.begin(), rTabNames.end());
++    
++    // data tables - preserve any existing data that may have been set during 
++    // Excel import.
++    vector<TableTypeRef> aNewTables(n);
++    for (size_t i = 0; i < n; ++i)
++    {
++        size_t nIndex;
++        if (lcl_getTableDataIndex(pDoc->maTableNameIndex, rTabNames[i], nIndex))
++        {
++            aNewTables[i] = pDoc->maTables[nIndex];
++        }
++    }
++    pDoc->maTables.swap(aNewTables);
++
++    // name index map
++    TableNameIndexMap aNewNameIndex;
++    for (size_t i = 0; i < n; ++i)
++        aNewNameIndex.insert(TableNameIndexMap::value_type(rTabNames[i], i));
++    pDoc->maTableNameIndex.swap(aNewNameIndex);
++
++    pDoc->mbInitFromSource = true;
++}
++
++const vector<String>* ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId) const
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    return &pDoc->maTableNames;
++}
++
++ScExternalRefCache::Table* ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew)
++{
++    DocItem* pDoc = getDocItem(nFileId);
++    if (!pDoc)
++        return NULL;
++
++    DocItem& rDoc = *pDoc;
++
++    size_t nIndex;
++    if (lcl_getTableDataIndex(rDoc.maTableNameIndex, rTabName, nIndex))
++        // specified table found.
++        return rDoc.maTables[nIndex].get();
++
++    if (!bCreateNew)
++        return NULL;
++
++    // Specified table doesn't exist yet.  Create one.
++    TableTypeRef pTab(new Table);
++    rDoc.maTables.push_back(pTab);
++    rDoc.maTableNames.push_back(rTabName);
++    rDoc.maTableNameIndex.insert(
++        TableNameIndexMap::value_type(rTabName, rDoc.maTables.size()-1));
++    return pTab.get();
++}
++
++void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
++{
++    maDocs.erase(nFileId);
++}
++
++ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
++{
++    using ::std::pair;
++    DocDataType::iterator itrDoc = maDocs.find(nFileId);
++    if (itrDoc == maDocs.end())
++    {
++        // specified document is not cached.
++        pair<DocDataType::iterator, bool> res = maDocs.insert(
++                DocDataType::value_type(nFileId, DocItem()));
++
++        if (!res.second)
++            // insertion failed.
++            return NULL;
++
++        itrDoc = res.first;
++    }
++
++    return &itrDoc->second;
++}
++
++// ============================================================================
++
++ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
++    ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
++    mnFileId(nFileId),
++    maFilterName(rFilter),
++    mpDoc(pDoc),
++    mbDoRefresh(true)
++{
++}
++
++ScExternalRefLink::~ScExternalRefLink()
++{
++}
++
++void ScExternalRefLink::Closed()
++{
++    ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
++    pMgr->removeSrcDocument(mnFileId, true);
++}
++
++void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
++{
++    if (!mbDoRefresh)
++        return;
++
++    String aFile, aFilter;
++    mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
++    ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
++    const String* pCurFile = pMgr->getExternalFileName(mnFileId);
++    if (!pCurFile)
++        return;
++
++    if (pCurFile->Equals(aFile))
++    {
++        // Refresh the current source document.
++        pMgr->refreshNames(mnFileId);
++    }
++    else
++    {
++        // The source document has changed.
++        pMgr->switchSrcFile(mnFileId, aFile);
++        maFilterName = aFilter;
++    }
++}
++
++void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
++{
++    SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, EndEditHdl));
++}
++
++void ScExternalRefLink::SetDoReferesh(bool b)
++{
++    mbDoRefresh = b;
++}
++
++IMPL_LINK(ScExternalRefLink, EndEditHdl, void*, EMPTYARG)
++{
++    return 0;
++}
++
++// ============================================================================
++
++static ScToken* lcl_convertToToken(ScBaseCell* pCell)
++{
++    if (!pCell)
++        return NULL;
++
++    switch (pCell->GetCellType())
++    {
++        case CELLTYPE_STRING:
++        {
++            String aStr;
++            static_cast<ScStringCell*>(pCell)->GetString(aStr);
++            ScStringToken aToken(aStr);
++            return aToken.Clone();
++        }
++        break;
++        case CELLTYPE_VALUE:
++        {
++            double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
++            ScDoubleToken aToken(fVal);
++            return aToken.Clone();
++        }
++        break;
++        case CELLTYPE_FORMULA:
++        {
++            ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
++            if (pFCell->IsValue())
++            {
++                double fVal = pFCell->GetValue();
++                ScDoubleToken aToken(fVal);
++                return aToken.Clone();
++            }
++            else
++            {
++                String aStr;
++                pFCell->GetString(aStr);
++                ScStringToken aToken(aStr);
++                return aToken.Clone();
++            }
++        }
++        break;
++        default:
++            DBG_ERROR("attempted to convert an unknown cell type.");
++    }
++
++    return NULL;
++}
++
++static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange, 
++                                             vector<ScExternalRefCache::SingleRangeData>& rCacheData)
++{
++    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();
++
++    auto_ptr<ScTokenArray> pArray(new ScTokenArray);
++    bool bFirstTab = true;
++    vector<ScExternalRefCache::SingleRangeData>::iterator 
++        itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
++    for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
++    {
++        ScMatrixRef xMat = new ScMatrix(
++            static_cast<SCSIZE>(nCol2-nCol1+1),
++            static_cast<SCSIZE>(nRow2-nRow1+1));
++
++        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
++        {
++            for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
++            {
++                SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
++                ScBaseCell* pCell;
++                pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
++                if (pCell)
++                {
++                    switch (pCell->GetCellType())
++                    {
++                        case CELLTYPE_STRING:
++                        {
++                            String aStr;
++                            static_cast<ScStringCell*>(pCell)->GetString(aStr);
++                            xMat->PutString(aStr, nC, nR);
++                        }
++                        break;
++                        case CELLTYPE_VALUE:
++                        {
++                            double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
++                            xMat->PutDouble(fVal, nC, nR);
++                        }
++                        break;
++                        case CELLTYPE_FORMULA:
++                        {
++                            ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
++                            if (pFCell->IsValue())
++                            {
++                                double fVal = pFCell->GetValue();
++                                xMat->PutDouble(fVal, nC, nR);
++                            }
++                            else
++                            {
++                                String aStr;
++                                pFCell->GetString(aStr);
++                                xMat->PutString(aStr, nC, nR);
++                            }
++                        }
++                        break;
++                        default:
++                            DBG_ERROR("attempted to convert an unknown cell type.");
++                    }
++                }
++                else
++                {
++                    xMat->PutEmpty(nC, nR);
++                }
++            }
++        }
++        if (!bFirstTab)
++            pArray->AddOpCode(ocSep);
++
++        ScMatrix* pMat2 = xMat;
++        ScMatrixToken aToken(pMat2);
++        pArray->AddToken(aToken);
++
++        itrCache->mpRangeData = xMat;
++
++        bFirstTab = false;
++    }
++    return pArray.release();
++}
++
++ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
++    mpDoc(pDoc)
++{
++    maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
++    maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
++}
++
++ScExternalRefManager::~ScExternalRefManager()
++{
++    clear();
++}
++
++ScExternalRefCache::Table* ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew)
++{
++    return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew);
++}
++
++void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
++{
++    ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
++    maRefCache.setRangeNameTokens(nFileId, rName, pArray);
++}
++
++ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
++                                                 const ScAddress* pCurPos, SCTAB* pTab)
++{
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
++
++    maybeLinkExternalFile(nFileId);
++
++    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)
++    {
++        return pToken;
++    }
++
++    // reference not cached.  read from the source document.
++    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    if (!pSrcDoc)
++    {
++        return NULL;
++    }
++
++    ScBaseCell* pCell = NULL;
++    SCTAB nTab;
++    if (!pSrcDoc->GetTable(rTabName, nTab))
++    {
++        // specified table name doesn't exist in the source document.
++        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();
++}
++
++ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
++{
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
++
++    maybeLinkExternalFile(nFileId);
++
++    // Check if the given table name and the cell position is cached.
++    ScTokenArray* p = maRefCache.getCellRangeData(nFileId, rTabName, rRange);
++    if (p)
++        return p;
++
++    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    if (!pSrcDoc)
++        return NULL;
++
++    SCTAB nTab1;
++    if (!pSrcDoc->GetTable(rTabName, nTab1))
++        // specified table name doesn't exist in the source document.
++        return NULL;
++
++    ScRange aRange(rRange);
++    SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
++
++    vector<ScExternalRefCache::SingleRangeData> aCacheData;
++    aCacheData.reserve(nTabSpan+1);
++    aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++    aCacheData.back().maTableName = rTabName;
++
++    for (SCTAB i = 1; i < nTabSpan + 1; ++i)
++    {
++        String aTabName;
++        if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
++            // source document doesn't have any table by the specified name.
++            break;
++
++        aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++        aCacheData.back().maTableName = aTabName;
++    }
++
++    aRange.aStart.SetTab(nTab1);
++    aRange.aEnd.SetTab(nTab1 + nTabSpan);
++
++    ScExternalRefCache::TokenArrayRef pArray;
++    pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
++
++    // Cache these values.
++    maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray);
++
++    return pArray.get();
++}
++
++ScTokenArray* ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
++{
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
++
++    maybeLinkExternalFile(nFileId);
++
++    ScTokenArray* pArray = maRefCache.getRangeNameTokens(nFileId, rName);
++    if (pArray)
++        return pArray;
++
++    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    if (!pSrcDoc)
++        return NULL;
++
++    ScRangeName* pExtNames = pSrcDoc->GetRangeName();
++    String aUpperName = ScGlobal::pCharClass->upper(rName);
++    USHORT n;
++    bool bRes = pExtNames->SearchNameUpper(aUpperName, n);
++    if (!bRes)
++        return NULL;
++
++    ScRangeData* pRangeData = (*pExtNames)[n];
++    if (!pRangeData)
++        return NULL;
++
++    // Parse all tokens in this external range data, and replace each absolute 
++    // reference token with an external reference token, and cache them.  Also
++    // register the source document with the link manager if it's a new
++    // source.
++
++    TokenArrayRef pNew(new ScTokenArray);
++
++    ScTokenArray* pCode = pRangeData->GetCode();
++    for (ScToken* pToken = pCode->First(); pToken; pToken = pCode->Next())
++    {
++        bool bTokenAdded = false;
++        switch (pToken->GetType())
++        {
++            case svSingleRef:
++            {
++                const SingleRefData& rRef = pToken->GetSingleRef();
++                String aTabName;
++                pSrcDoc->GetName(rRef.nTab, aTabName);
++                ScExternalSingleRefToken aNewToken(nFileId, aTabName, pToken->GetSingleRef());
++                pNew->AddToken(aNewToken);
++                bTokenAdded = true;
++            }
++            break;
++            case svDoubleRef:
++            {
++                const SingleRefData& rRef = pToken->GetSingleRef();
++                String aTabName;
++                pSrcDoc->GetName(rRef.nTab, aTabName);
++                ScExternalDoubleRefToken aNewToken(nFileId, aTabName, pToken->GetDoubleRef());
++                pNew->AddToken(aNewToken);
++                bTokenAdded = true;
++            }
++            break;
++            default:
++                ; // nothing to do
++        }
++        
++        if (!bTokenAdded)
++            pNew->AddToken(*pToken);
++    }
++
++    maRefCache.setRangeNameTokens(nFileId, rName, pNew);
++    return pNew.get();
++}
++
++void ScExternalRefManager::refreshAllReferencingCells(sal_uInt16 nFileId)
++{
++    RefCellMap::iterator itr = maRefCells.find(nFileId);
++    if (itr == maRefCells.end())
++        return;
++
++    RefCellSet aNewSet;
++    RefCellSet& rSet = itr->second;
++    RefCellSet::const_iterator itrSet = rSet.begin(), itrSetEnd = rSet.end();
++    for (; itrSet != itrSetEnd; ++itrSet)
++    {
++        if (compileTokensByCell(*itrSet))
++            // Cell still contains an external name/ref token.
++            aNewSet.insert(*itrSet);
++    }
++    rSet.swap(aNewSet);
++
++    ScViewData* pViewData = ScDocShell::GetViewData();
++    if (!pViewData)
++        return;
++
++    ScTabViewShell* pVShell = pViewData->GetViewShell();
++    if (!pVShell)
++        return;
++
++    // Repainting the grid also repaints the texts, but is there a better way
++    // to refresh texts?
++    pVShell->Invalidate(FID_TAB_TOGGLE_GRID);
++    pVShell->PaintGrid();
++}
++
++void ScExternalRefManager::insertReferencingCell(sal_uInt16 nFileId, const ScAddress& rCell)
++{
++    RefCellMap::iterator itr = maRefCells.find(nFileId);
++    if (itr != maRefCells.end())
++    {
++        itr->second.insert(rCell);
++        return;
++    }
++
++    RefCellSet aSet;
++    aSet.insert(rCell);
++    maRefCells.insert(RefCellMap::value_type(nFileId, aSet));
++}
++
++ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
++{
++    DocShellMap::iterator itrEnd = maDocShells.end();
++    DocShellMap::iterator itr = maDocShells.find(nFileId);
++
++    if (itr != itrEnd)
++    {
++        SfxObjectShell* p = itr->second.maShell;
++        itr->second.maLastAccess = Time();
++        return static_cast<ScDocShell*>(p)->GetDocument();
++    }
++
++    const String* pFile = getExternalFileName(nFileId);
++    if (!pFile)
++        // no file name associated with this ID.
++        return NULL;
++
++    String aFilter;
++    SrcShell aSrcDoc;
++    aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
++    if (!aSrcDoc.maShell.Is())
++    {
++        // source document could not be loaded.
++        return NULL;
++    }
++
++    if (maDocShells.empty())
++    {
++        // If this is the first source document insertion, start up the timer.
++        maSrcDocTimer.Start();
++    }
++
++    maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
++    SfxObjectShell* p = aSrcDoc.maShell;
++    ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
++
++    SCTAB nTabCount = pSrcDoc->GetTableCount();
++    if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
++    {
++        // Populate the cache with all table names in the source document.
++        vector<String> aTabNames;
++        aTabNames.reserve(nTabCount);
++        for (SCTAB i = 0; i < nTabCount; ++i)
++        {
++            String aName;
++            pSrcDoc->GetName(i, aName);
++            aTabNames.push_back(aName);
++        }
++        maRefCache.initializeDoc(nFileId, aTabNames);
++    }
++    return pSrcDoc;
++}
++
++SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter)
++{
++    const SrcFileData* pFileData = getExternalFileData(nFileId);
++    if (!pFileData)
++        return NULL;
++
++    String aFile = pFileData->maFileName;
++    if (!isFileLoadable(aFile))
++    {
++        // The original file path is not loadable.  Try the relative path.  
++        // Note that the path is relative to the content.xml substream which
++        // is one-level higher than the file itself.
++
++        if (!pFileData->maRelativeName.Len())
++            return NULL;
++
++        INetURLObject aBaseURL(getOwnDocumentName());
++        aBaseURL.insertName(OUString::createFromAscii("content.xml"));
++        bool bWasAbs = false;
++        aFile = aBaseURL.smartRel2Abs(pFileData->maRelativeName, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
++        if (!isFileLoadable(aFile))
++            // Ok, I've tried both paths but no success.  Bail out.
++            return NULL;
++    }
++
++    String aOptions;
++    ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
++    const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
++
++    if (!pFileData->maRelativeName.Len())
++    {
++        // Generate a relative file path.
++        INetURLObject aBaseURL(getOwnDocumentName());
++        aBaseURL.insertName(OUString::createFromAscii("content.xml"));
++
++        String aStr = URIHelper::simpleNormalizedMakeRelative(
++            aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
++
++        setRelativeFileName(nFileId, aStr);
++    }
++
++    // Update the filter data now that we are loading it again.
++    setFilterData(nFileId, rFilter, aOptions);
++
++    SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
++    if (aOptions.Len())
++        pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
++
++    auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet));
++    if (pMedium->GetError() != ERRCODE_NONE)
++        return NULL;
++
++    pMedium->UseInteractionHandler(false);
++
++    ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
++    SfxObjectShellRef aRef = pNewShell;
++
++    // increment the recursive link count of the source document.
++    ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
++    sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
++    ScDocument* pSrcDoc = pNewShell->GetDocument();
++    ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
++    if (!pExtOptNew)
++    {
++        pExtOptNew = new ScExtDocOptions;
++        pSrcDoc->SetExtDocOptions(pExtOptNew);
++    }
++    pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
++
++    pNewShell->DoLoad(pMedium.release());
++    return aRef;
++}
++
++bool ScExternalRefManager::isFileLoadable(const String& rFile) const
++{
++    if (isOwnDocument(rFile))
++        return false;
++
++    if (utl::UCBContentHelper::IsFolder(rFile))
++        return false;
++
++    return utl::UCBContentHelper::Exists(rFile);
++}
++
++void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
++{
++    if (maLinkedDocs.count(nFileId))
++        // file alerady linked.
++        return;
++
++    // Source document not linked yet.  Link it now.
++    const String* pFileName = getExternalFileName(nFileId);
++    if (!pFileName)
++        return;
++
++    String aFilter, aOptions;
++    ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
++    SvxLinkManager* pLinkMgr = mpDoc->GetLinkManager();
++    ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
++    DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
++    pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter);
++
++    pLink->SetDoReferesh(false);
++    pLink->Update();
++    pLink->SetDoReferesh(true);
++
++    maLinkedDocs.insert(nFileId);
++}
++
++bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell)
++{
++    ScBaseCell* pCell;
++    mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
++
++    if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA)
++        return false;
++
++    ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
++
++    // Check to make sure the cell really contains ocExternalName.
++    bool bCompile = false;
++    ScTokenArray* pCode = pFC->GetCode();
++    pCode->Reset();
++    for (ScToken* p = pCode->First(); p; p = pCode->Next())
++    {
++        // External names, external cell and range references all have a 
++        // ocExternalName token.
++        if (p->GetOpCode() == ocExternalName)
++        {
++            bCompile = true;
++            break;
++        }
++    }
++    if (!bCompile)
++        return false;
++
++    ScTokenArray* pArray = pFC->GetCode();
++    if (pArray)
++        // Clear the error code, or a cell with error won't get re-compiled.
++        pArray->SetCodeError(0);
++
++    pFC->SetCompile(true);
++    pFC->CompileTokenArray();
++    pFC->SetDirty();
++
++    return true;
++}
++
++const String& ScExternalRefManager::getOwnDocumentName() const
++{
++    SfxObjectShell* pShell = mpDoc->GetDocumentShell();
++    if (!pShell)
++        // This should not happen!
++        return EMPTY_STRING;
++
++    SfxMedium* pMed = pShell->GetMedium();
++    if (!pMed)
++        return EMPTY_STRING;
++
++    return pMed->GetName();
++}
++
++bool ScExternalRefManager::isOwnDocument(const String& rFile) const
++{
++    return getOwnDocumentName().Equals(rFile);
++}
++
++void ScExternalRefManager::convertToAbsName(String& rFile) const
++{
++    SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
++    rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
++}
++
++namespace {
++
++class FindSrcFileByName : public ::std::unary_function<ScExternalRefManager::SrcFileData, bool>
++{
++public:
++    FindSrcFileByName(const String& rMatchName) :
++        mrMatchName(rMatchName)
++    {
++    }
++
++    bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
++    {
++        return rSrcData.maFileName.Equals(mrMatchName);
++    }
++
++private:
++    const String& mrMatchName;
++};
++
++}
++sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile)
++{
++    using namespace std;
++
++    vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
++    vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
++    if (itr != itrEnd)
++    {
++        size_t nId = distance(itrBeg, itr);
++        return static_cast<sal_uInt16>(nId);
++    }
++
++    SrcFileData aData;
++    aData.maFileName = rFile;
++    maSrcFiles.push_back(aData);
++    return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
++}
++
++const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId) const
++{
++    if (nFileId >= maSrcFiles.size())
++        return NULL;
++
++    return &maSrcFiles[nFileId].maFileName;
++}
++
++const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
++{
++    if (nFileId >= maSrcFiles.size())
++        return NULL;
++
++    return &maSrcFiles[nFileId];
++}
++
++const vector<String>* ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId) const
++{
++    return maRefCache.getAllTableNames(nFileId);
++}
++
++sal_uInt16 ScExternalRefManager::getCachedFileCount() const
++{
++    return static_cast<sal_uInt16>(maSrcFiles.size());
++}
++
++template<typename MapContainer>
++static void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
++{
++    typename MapContainer::iterator itr = rMap.find(nFileId);
++    if (itr != rMap.end())
++        rMap.erase(itr);
++}
++
++void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
++{
++    removeSrcDocument(nFileId, false);
++
++    // Update all cells containing names from this source document.
++    refreshAllReferencingCells(nFileId);
++}
++
++void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile)
++{
++    maSrcFiles[nFileId].maFileName = rNewFile;
++    maSrcFiles[nFileId].maRelativeName.Erase();
++    refreshNames(nFileId);
++}
++
++void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl)
++{
++    if (nFileId >= maSrcFiles.size())
++        return;
++    maSrcFiles[nFileId].maRelativeName = rRelUrl;
++}
++
++void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions)
++{
++    if (nFileId >= maSrcFiles.size())
++        return;
++    maSrcFiles[nFileId].maFilterName = rFilterName;
++    maSrcFiles[nFileId].maFilterOptions = rOptions;
++}
++
++void ScExternalRefManager::removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink)
++{
++    maRefCache.clearCache(nFileId);
++    lcl_removeByFileId(nFileId, maDocShells);
++
++    if (bBreakLink)
++        maLinkedDocs.erase(nFileId);
++
++    if (maDocShells.empty())
++        maSrcDocTimer.Stop();
++}
++
++void ScExternalRefManager::clear()
++{
++    DocShellMap::iterator itrEnd = maDocShells.end();
++    for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
++        itr->second.maShell->DoClose();
++
++    maDocShells.clear();
++    maSrcDocTimer.Stop();
++}
++
++bool ScExternalRefManager::hasExternalData() const
++{
++    return !maSrcFiles.empty();
++}
++
++void ScExternalRefManager::resetSrcFileData()
++{
++    INetURLObject aBaseURL(getOwnDocumentName());
++    aBaseURL.insertName(OUString::createFromAscii("content.xml"));
++    String aBaseUrlStr = aBaseURL.GetMainURL(INetURLObject::NO_DECODE);
++    for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
++          itr != itrEnd; ++itr)
++    {
++        if (!itr->maRelativeName.Len())
++        {
++            itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
++                aBaseUrlStr, itr->maFileName);
++        }
++    }
++}
++
++void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
++{
++    DocShellMap aNewDocShells;
++    DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
++    for (; itr != itrEnd; ++itr)
++    {
++        // in 100th of a second.
++        sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime(); 
++        if (nSinceLastAccess < nTimeOut)
++            aNewDocShells.insert(*itr);
++    }
++    maDocShells.swap(aNewDocShells);
++
++    if (maDocShells.empty())
++        maSrcDocTimer.Stop();
++}
++
++IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
++{
++    if (pTimer == &maSrcDocTimer)
++        purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
++
++    return 0;
++}
++
+diff --git sc/source/ui/docshell/makefile.mk sc/source/ui/docshell/makefile.mk
+index db83fec..6286dfb 100644
+--- sc/source/ui/docshell/makefile.mk
++++ sc/source/ui/docshell/makefile.mk
+@@ -53,6 +53,7 @@ CXXFILES = \
+         docsh6.cxx 	\
+         docsh7.cxx 	\
+         docsh8.cxx 	\
++        externalrefmgr.cxx \
+         tablink.cxx 	\
+         arealink.cxx 	\
+         dbdocfun.cxx 	\
+@@ -79,6 +80,7 @@ SLOFILES =  \
+         $(SLO)$/docsh6.obj   	\
+         $(SLO)$/docsh7.obj   	\
+         $(SLO)$/docsh8.obj   	\
++        $(SLO)$/externalrefmgr.obj \
+         $(SLO)$/tablink.obj   	\
+         $(SLO)$/arealink.obj   	\
+         $(SLO)$/dbdocfun.obj 	\
+@@ -101,6 +103,7 @@ EXCEPTIONSFILES= \
+         $(SLO)$/docsh3.obj	\
+         $(SLO)$/docsh4.obj \
+         $(SLO)$/docsh8.obj \
++        $(SLO)$/externalrefmgr.obj \
+         $(SLO)$/dbdocimp.obj
+ 
+ SRS1NAME=$(TARGET)
+@@ -117,6 +120,7 @@ LIB1OBJFILES =  \
+         $(SLO)$/docsh6.obj   	\
+         $(SLO)$/docsh7.obj   	\
+         $(SLO)$/docsh8.obj   	\
++        $(SLO)$/externalrefmgr.obj \
+         $(SLO)$/tablink.obj   	\
+         $(SLO)$/arealink.obj   	\
+         $(SLO)$/dbdocfun.obj 	\
+diff --git sc/source/ui/unoobj/docuno.cxx sc/source/ui/unoobj/docuno.cxx
+index 5a8c983..6a2fabf 100644
+--- sc/source/ui/unoobj/docuno.cxx
++++ sc/source/ui/unoobj/docuno.cxx
+@@ -123,6 +123,7 @@ const SfxItemPropertyMap* lcl_GetDocOptPropertyMap()
+         {MAP_CHAR_LEN(SC_UNO_COLLABELRNG),       0, &getCppuType((uno::Reference<sheet::XLabelRanges>*)0),    0, 0},
+         {MAP_CHAR_LEN(SC_UNO_DDELINKS),          0, &getCppuType((uno::Reference<container::XNameAccess>*)0), 0, 0},
+         {MAP_CHAR_LEN(SC_UNO_DEFTABSTOP),        0, &getCppuType((sal_Int16*)0),                              0, 0},
++        {MAP_CHAR_LEN(SC_UNO_EXTERNALDOCLINKS),  0, &getCppuType((uno::Reference<sheet::XExternalDocLinks>*)0), 0, 0},
+         {MAP_CHAR_LEN(SC_UNO_FORBIDDEN),         0, &getCppuType((uno::Reference<i18n::XForbiddenCharacters>*)0), beans::PropertyAttribute::READONLY, 0},
+         {MAP_CHAR_LEN(SC_UNO_HASDRAWPAGES),      0, &getBooleanCppuType(),                                    beans::PropertyAttribute::READONLY, 0},
+         {MAP_CHAR_LEN(SC_UNO_IGNORECASE),        0, &getBooleanCppuType(),                                    0, 0},
+@@ -1537,6 +1538,10 @@ uno::Any SAL_CALL ScModelObj::getPropertyValue( const rtl::OUString& aPropertyNa
+ 		{
+ 			aRet <<= uno::Reference<container::XNameAccess>(new ScDDELinksObj( pDocShell ));
+ 		}
++        else if ( aString.EqualsAscii( SC_UNO_EXTERNALDOCLINKS ) )
++        {
++            aRet <<= uno::Reference<sheet::XExternalDocLinks>(new ScExternalDocLinksObj(pDocShell));
++        }
+ 		else if ( aString.EqualsAscii( SC_UNO_SHEETLINKS ) )
+ 		{
+ 			aRet <<= uno::Reference<container::XNameAccess>(new ScSheetLinksObj( pDocShell ));
+diff --git sc/source/ui/unoobj/linkuno.cxx sc/source/ui/unoobj/linkuno.cxx
+index 52a5a62..96a074e 100644
+--- sc/source/ui/unoobj/linkuno.cxx
++++ sc/source/ui/unoobj/linkuno.cxx
+@@ -48,8 +48,20 @@
+ #include "hints.hxx"
+ #include "unonames.hxx"
+ #include "rangeseq.hxx"
++#include "token.hxx"
++
++#include <vector>
+ 
+ using namespace com::sun::star;
++using ::com::sun::star::uno::Any;
++using ::com::sun::star::uno::Reference;
++using ::com::sun::star::uno::Sequence;
++using ::com::sun::star::uno::UNO_QUERY;
++using ::com::sun::star::uno::UNO_QUERY_THROW;
++using ::com::sun::star::lang::IllegalArgumentException;
++using ::com::sun::star::uno::RuntimeException;
++using ::rtl::OUString;
++using ::std::vector;
+ 
+ //------------------------------------------------------------------------
+ 
+@@ -1480,4 +1492,223 @@ uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink(
+     return xLink;
+ }
+ 
+-//------------------------------------------------------------------------
++// ============================================================================
++
++ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScExternalRefCache::Table* pTable) :
++    mpTable(pTable)
++{
++}
++
++ScExternalSheetCacheObj::~ScExternalSheetCacheObj()
++{
++}
++
++void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nRow, sal_Int32 nCol, const Any& rValue)
++    throw (IllegalArgumentException, RuntimeException)
++{
++    ScUnoGuard aGuard;
++    if (nRow < 0 || nCol < 0)
++        throw IllegalArgumentException();
++
++    ScExternalRefCache::TokenRef pToken;
++    double fVal;
++    OUString aVal;
++    if (rValue >>= fVal)
++        pToken.reset(new ScDoubleToken(fVal));
++    else if (rValue >>= aVal)
++        pToken.reset(new ScStringToken(aVal));
++    else
++        // unidentified value type.
++        return;
++
++    mpTable->setCell(static_cast<SCROW>(nRow), static_cast<SCCOL>(nCol), pToken);
++}
++
++Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nRow, sal_Int32 nCol)
++    throw (IllegalArgumentException, RuntimeException)
++{
++    ScUnoGuard aGuard;
++    if (nRow < 0 || nCol < 0)
++        throw IllegalArgumentException();
++
++    ScToken* pToken = mpTable->getCell(nRow, nCol).get();
++    if (!pToken)
++        throw IllegalArgumentException();
++
++    Any aValue;
++    switch (pToken->GetType())
++    {
++        case svDouble:
++        {
++            double fVal = pToken->GetDouble();
++            aValue <<= fVal;
++        }
++        break;
++        case svString:
++        {
++            OUString aVal = pToken->GetString();
++            aValue <<= aVal;
++        }
++        break;
++        default:
++            throw IllegalArgumentException();
++    }
++    return aValue;
++}
++
++Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows()
++    throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    vector<SCROW> aRows;
++    mpTable->getAllRows(aRows);
++    size_t nSize = aRows.size();
++    Sequence<sal_Int32> aRowsSeq(nSize);
++    for (size_t i = 0; i < nSize; ++i)
++        aRowsSeq[i] = aRows[i];
++
++    return aRowsSeq;
++}
++
++Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow)
++    throw (IllegalArgumentException, RuntimeException)
++{
++    ScUnoGuard aGuard;
++    if (nRow < 0)
++        throw IllegalArgumentException();
++
++    vector<SCCOL> aCols;
++    mpTable->getAllCols(static_cast<SCROW>(nRow), aCols);
++    size_t nSize = aCols.size();
++    Sequence<sal_Int32> aColsSeq(nSize);
++    for (size_t i = 0; i < nSize; ++i)
++        aColsSeq[i] = aCols[i];
++
++    return aColsSeq;
++}
++
++// ============================================================================
++
++ScExternalDocLinkObj::ScExternalDocLinkObj(ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) :
++    mpRefMgr(pRefMgr), mnFileId(nFileId)
++{
++}
++
++ScExternalDocLinkObj::~ScExternalDocLinkObj()
++{
++}
++
++Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache(
++    const OUString& aSheetName )
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    ScExternalRefCache::Table* pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true);
++    Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable));
++    return aSheetCache;
++}
++
++// ============================================================================
++
++ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) :
++    mpDocShell(pDocShell),
++    mpRefMgr(pDocShell->GetDocument()->GetExternalRefManager())
++{
++}
++
++ScExternalDocLinksObj::~ScExternalDocLinksObj()
++{
++}
++
++Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink(
++    const OUString& aDocName )
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocName);
++    Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId));
++    maDocLinks.insert( DocLinkMap::value_type(aDocName, aDocLink) );
++    maDocNames.push_back(aDocName);
++    return aDocLink;
++}
++
++Any SAL_CALL ScExternalDocLinksObj::getByName(const::rtl::OUString &aName) 
++        throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
++{
++    ScUnoGuard aGuard;
++    DocLinkMap::const_iterator itr = maDocLinks.find(aName);
++    if (itr == maDocLinks.end())
++        throw container::NoSuchElementException();
++
++    Any aAny;
++    aAny <<= itr->second;
++    return aAny;
++}
++
++Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames() 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    size_t n = maDocNames.size();
++    Sequence<OUString> aSeq(n);
++    for (size_t i = 0; i < n; ++i)
++        aSeq[i] = maDocNames[i];
++    return aSeq;
++}
++
++sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName) 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    return static_cast<sal_Bool>(maDocLinks.count(aName) > 0);
++}
++
++sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount() 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    return static_cast<sal_Int32>(maDocLinks.size());
++}
++
++Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex) 
++        throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, RuntimeException)
++{
++    ScUnoGuard aGuard;
++    if (nIndex < 0 || nIndex >= static_cast<sal_Int32>(maDocNames.size()))
++        throw lang::IndexOutOfBoundsException();
++
++    const OUString& rDocName = maDocNames[nIndex];
++    DocLinkMap::const_iterator itr = maDocLinks.find(rDocName);
++    if (itr == maDocLinks.end())
++        // This should never happen!
++        throw lang::IndexOutOfBoundsException();
++
++    Any aAny;
++    aAny <<= itr->second;
++    return aAny;
++}
++
++Reference< container::XEnumeration >SAL_CALL ScExternalDocLinksObj::createEnumeration() 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    Reference< container::XEnumeration > aRef(
++        new ScIndexEnumeration(this, OUString::createFromAscii(
++            "com.sun.star.sheet.ExternalDocLinks")));
++    return aRef;
++}
++
++uno::Type SAL_CALL ScExternalDocLinksObj::getElementType() 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    return getCppuType(static_cast<Reference<sheet::XExternalDocLinks>*>(0));
++}
++
++sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements() 
++        throw (RuntimeException)
++{
++    ScUnoGuard aGuard;
++    return static_cast<sal_Bool>(!maDocLinks.empty());
++}
++
+diff --git sc/source/ui/view/tabvwsh4.cxx sc/source/ui/view/tabvwsh4.cxx
+index 436f0eb..2bf1f26 100644
+--- sc/source/ui/view/tabvwsh4.cxx
++++ sc/source/ui/view/tabvwsh4.cxx
+@@ -100,6 +100,7 @@
+ #include "navsett.hxx"
+ #include "sc.hrc" //CHINA001
+ #include "scabstdlg.hxx" //CHINA001
++#include "externalrefmgr.hxx"
+ 
+ void ActivateOlk( ScViewData* pViewData );
+ void DeActivateOlk( ScViewData* pViewData );
+@@ -1833,11 +1834,8 @@ void ScTabViewShell::Construct( BYTE nForceDesignMode )
+ 		if ( pDocSh->GetCreateMode() != SFX_CREATE_MODE_INTERNAL &&
+              pDocSh->IsUpdateEnabled() )  // #105575#; update only in the first creation of the ViewShell
+ 		{
+-			BOOL bLink = FALSE;									// Links updaten
+-			SCTAB nTabCount = pDoc->GetTableCount();
+-			for (SCTAB i=0; i<nTabCount && !bLink; i++)
+-				if (pDoc->IsLinked(i))
+-					bLink = TRUE;
++            // Check if there are any external data.
++            bool bLink = pDoc->GetExternalRefManager()->hasExternalData();
+ 			if (!bLink)
+ 				if (pDoc->HasDdeLinks() || pDoc->HasAreaLinks())
+ 					bLink = TRUE;

Added: trunk/patches/test/calc-external-names-additional-fixes-before-merge.diff
==============================================================================
--- (empty file)
+++ trunk/patches/test/calc-external-names-additional-fixes-before-merge.diff	Tue Sep  2 19:07:24 2008
@@ -0,0 +1,164 @@
+diff --git sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx
+index f675389..6aff7ad 100644
+--- sc/source/core/tool/compiler.cxx
++++ sc/source/core/tool/compiler.cxx
+@@ -1298,16 +1298,22 @@ static bool lcl_parseExternalName( const String& rSymbol, String& rFile, String&
+     return true;
+ }
+ 
+-static String lcl_makeExternalNameStr( const String& rFile, const String& rName, const sal_Unicode cSep )
++static String lcl_makeExternalNameStr( const String& rFile, const String& rName,
++        const sal_Unicode cSep, bool bODF )
+ {
+-    String aStr, aFile = rFile;
++    String aFile( rFile);
+     aFile.SearchAndReplaceAllAscii("'", String::CreateFromAscii("''"));
+-    aStr.Append(sal_Unicode('\''));
+-    aStr.Append(aFile);
+-    aStr.Append(sal_Unicode('\''));
+-    aStr.Append(cSep);
+-    aStr.Append(rName);
+-    return aStr;
++    rtl::OUStringBuffer aBuf( aFile.Len() + rName.Len() + 5);
++    if (bODF)
++        aBuf.append( sal_Unicode( '['));
++    aBuf.append( sal_Unicode( '\''));
++    aBuf.append( aFile);
++    aBuf.append( sal_Unicode( '\''));
++    aBuf.append( cSep);
++    aBuf.append( rName);
++    if (bODF)
++        aBuf.append( sal_Unicode(']'));
++    return String( aBuf.makeStringAndClear());
+ }
+ 
+ static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1, 
+@@ -1561,7 +1567,7 @@ struct ConventionOOO_A1 : public Convention_A1
+ 
+     virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
+     {
+-        return lcl_makeExternalNameStr(rFile, rName, sal_Unicode('#'));
++        return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), false);
+     }
+ 
+     bool makeExternalSingleRefStr( ::rtl::OUStringBuffer& rBuffer, sal_uInt16 nFileId, 
+@@ -1598,40 +1604,67 @@ struct ConventionOOO_A1 : public Convention_A1
+         return true;
+     }
+ 
+-    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++    void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+                                      sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
+-                                     ScExternalRefManager* pRefMgr ) const
++                                     ScExternalRefManager* pRefMgr, bool bODF ) const
+     {
+         SingleRefData aRef(rRef);
+         aRef.CalcAbsIfRel(rCompiler.GetPos());
+ 
++        if (bODF)
++            rBuffer.append( sal_Unicode('['));
+         makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef, pRefMgr, true);
++        if (bODF)
++            rBuffer.append( sal_Unicode(']'));
+     }
+ 
+     virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
+-                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
+                                      ScExternalRefManager* pRefMgr ) const
+     {
++        makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false);
++    }
++
++    void makeExternalRefStrImpl( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr, bool bODF ) const
++    {
+         ComplRefData aRef(rRef);
+         aRef.CalcAbsIfRel(rCompiler.GetPos());
+ 
+-        if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true))
+-            return;
++        if (bODF)
++            rBuffer.append( sal_Unicode('['));
++        // Ensure that there's always a closing bracket, no premature returns.
++        do
++        {
++            if (!makeExternalSingleRefStr(rBuffer, nFileId, rTabName, aRef.Ref1, pRefMgr, true))
++                break;
+ 
+-        rBuffer.append(sal_Unicode(':'));
++            rBuffer.append(sal_Unicode(':'));
+ 
+-        // Get the name of the last table.
+-        const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
+-        if (!pTabNames)
+-            return;
++            // Get the name of the last table.
++            const vector<String>* pTabNames = pRefMgr->getAllCachedTableNames(nFileId);
++            if (!pTabNames)
++                break;
+ 
+-        String aLastTabName;
+-        if (!lcl_getLastTabName(aLastTabName, rTabName, *pTabNames, aRef))
+-        {
+-            rBuffer.append(aLastTabName);
+-            return;
+-        }
+-        makeExternalSingleRefStr(rBuffer, nFileId, aLastTabName, aRef.Ref2, pRefMgr, (aRef.Ref1.nTab != aRef.Ref2.nTab));
++            String aLastTabName;
++            if (!lcl_getLastTabName(aLastTabName, rTabName, *pTabNames, aRef))
++            {
++                rBuffer.append(aLastTabName);
++                break;
++            }
++            makeExternalSingleRefStr( rBuffer, nFileId, aLastTabName,
++                    aRef.Ref2, pRefMgr, (aRef.Ref1.nTab != aRef.Ref2.nTab));
++        } while (0);
++        if (bODF)
++            rBuffer.append( sal_Unicode(']'));
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, false);
+     }
+ };
+ 
+@@ -1651,6 +1684,25 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1
+     {
+         MakeRefStrImpl( rBuffer, rComp, rRef, bSingleRef, true);
+     }
++
++    virtual String makeExternalNameStr( const String& rFile, const String& rName ) const
++    {
++        return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('#'), true);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const SingleRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true);
++    }
++
++    virtual void makeExternalRefStr( ::rtl::OUStringBuffer& rBuffer, const ScCompiler& rCompiler,
++                                     sal_uInt16 nFileId, const String& rTabName, const ComplRefData& rRef, 
++                                     ScExternalRefManager* pRefMgr ) const
++    {
++        makeExternalRefStrImpl( rBuffer, rCompiler, nFileId, rTabName, rRef, pRefMgr, true);
++    }
+ };
+ 
+ static const ConventionOOO_A1_ODF ConvOOO_A1_ODF;
+@@ -1762,7 +1814,7 @@ struct ConventionXL
+ 
+     static String makeExternalNameStr( const String& rFile, const String& rName )
+     {
+-        return lcl_makeExternalNameStr(rFile, rName, sal_Unicode('!'));
++        return lcl_makeExternalNameStr( rFile, rName, sal_Unicode('!'), false);
+     }
+ 
+     static void makeExternalDocStr( ::rtl::OUStringBuffer& rBuffer, const String& rFullName )



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