ooo-build r13761 - trunk/patches/test
- From: kyoshida svn gnome org
- To: svn-commits-list gnome org
- Subject: ooo-build r13761 - trunk/patches/test
- Date: Tue, 2 Sep 2008 19:07:24 +0000 (UTC)
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]