summaryrefslogtreecommitdiff
path: root/sc/source/filter/excel/xelink.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel/xelink.cxx')
-rw-r--r--sc/source/filter/excel/xelink.cxx2371
1 files changed, 2371 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx
new file mode 100644
index 000000000000..fcf738527025
--- /dev/null
+++ b/sc/source/filter/excel/xelink.cxx
@@ -0,0 +1,2371 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * 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 "xelink.hxx"
+
+#include <algorithm>
+#include <unotools/collatorwrapper.hxx>
+#include <svl/zforlist.hxx>
+#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;
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+
+// ============================================================================
+// *** Helper classes ***
+// ============================================================================
+
+// External names =============================================================
+
+/** This is a base class for any external name (i.e. add-in names or DDE links).
+ @descr Derived classes implement creation and export of the external names. */
+class XclExpExtNameBase : public XclExpRecord, protected XclExpRoot
+{
+public:
+ /** @param nFlags The flags to export. */
+ explicit XclExpExtNameBase( const XclExpRoot& rRoot,
+ const String& rName, sal_uInt16 nFlags = 0 );
+ virtual ~XclExpExtNameBase();
+
+ /** Returns the name string of the external name. */
+ inline const String& GetName() const { return maName; }
+
+private:
+ /** Writes the start of the record that is equal in all EXTERNNAME records and calls WriteAddData(). */
+ virtual void WriteBody( XclExpStream& rStrm );
+ /** Called to write additional data following the common record contents.
+ @descr Derived classes should overwrite this function to write their data. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+
+private:
+ String maName; /// Calc name (title) of the external name.
+ XclExpStringRef mxName; /// Excel name (title) of the external name.
+ sal_uInt16 mnFlags; /// Flags for record export.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents an EXTERNNAME record for an add-in function name. */
+class XclExpExtNameAddIn : public XclExpExtNameBase
+{
+public:
+ explicit XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName );
+
+private:
+ /** Writes additional record contents. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents an EXTERNNAME record for a DDE link. */
+class XclExpExtNameDde : public XclExpExtNameBase
+{
+public:
+ explicit XclExpExtNameDde( const XclExpRoot& rRoot, const String& rName,
+ sal_uInt16 nFlags, const ScMatrix* pResults = 0 );
+
+private:
+ /** Writes additional record contents. */
+ virtual void WriteAddData( XclExpStream& rStrm );
+
+private:
+ typedef ScfRef< XclExpCachedMatrix > XclExpCachedMatRef;
+ 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 ScExternalRefCache::TokenArrayRef 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. */
+class XclExpExtNameBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpExtNameBuffer( const XclExpRoot& rRoot );
+
+ /** Inserts an add-in function name
+ @return The 1-based (Excel-like) list index of the name. */
+ sal_uInt16 InsertAddIn( const String& rName );
+ /** InsertEuroTool */
+ sal_uInt16 InsertEuroTool( const String& rName );
+ /** Inserts a DDE link.
+ @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 ScExternalRefCache::TokenArrayRef pArray );
+
+ /** Writes the EXTERNNAME record list. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpExtNameBase > XclExpExtNameList;
+ typedef XclExpExtNameList::RecordRefType XclExpExtNameRef;
+
+private:
+ /** Returns the 1-based (Excel-like) list index of the external name or 0, if not found. */
+ sal_uInt16 GetIndex( const String& rName ) const;
+ /** Appends the passed newly crested external name.
+ @return The 1-based (Excel-like) list index of the appended name. */
+ sal_uInt16 AppendNew( XclExpExtNameBase* pExtName );
+
+private:
+ XclExpExtNameList maNameList; /// The list with all EXTERNNAME records.
+};
+
+// Cached external cells ======================================================
+
+/** Stores the contents of a consecutive row of external cells (record CRN). */
+class XclExpCrn : public XclExpRecord
+{
+public:
+ explicit XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+
+ /** Returns true, if the passed value could be appended to this record. */
+ bool InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+
+private:
+ virtual void WriteBody( XclExpStream& rStrm );
+
+ void WriteBool( XclExpStream& rStrm, bool bValue );
+ void WriteDouble( XclExpStream& rStrm, double fValue );
+ void WriteString( XclExpStream& rStrm, const OUString& rValue );
+ void WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode );
+ void WriteEmpty( XclExpStream& rStrm );
+
+private:
+ typedef ::std::vector< Any > CachedValues;
+
+ CachedValues maValues; /// All cached values.
+ SCCOL mnScCol; /// Column index of the first external cell.
+ SCROW mnScRow; /// Row index of the external cells.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Represents the record XCT which is the header record of a CRN record list.
+ */
+class XclExpXct : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpXct( const XclExpRoot& rRoot,
+ const String& rTabName, sal_uInt16 nSBTab,
+ ScExternalRefCache::TableTypeRef xCacheTable );
+
+ /** Returns the external sheet name. */
+ inline const XclExpString& GetTabName() const { return maTabName; }
+
+ /** Stores all cells in the given range in the CRN list. */
+ void StoreCellRange( const ScRange& rRange );
+
+ void StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken );
+ void StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken );
+
+ /** Writes the XCT and all CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ ScExternalRefCache::TableTypeRef mxCacheTable;
+ ScMarkData maUsedCells; /// Contains addresses of all stored cells.
+ ScRange maBoundRange; /// Bounding box of maUsedCells.
+ XclExpString maTabName; /// Sheet name of the external sheet.
+ sal_uInt16 mnSBTab; /// Referred sheet index in SUPBOOK record.
+};
+
+// External documents (EXTERNSHEET/SUPBOOK), base class =======================
+
+/** Base class for records representing external sheets/documents.
+
+ In BIFF5/BIFF7, this record is the EXTERNSHEET record containing one sheet
+ of the own or an external document. In BIFF8, this record is the SUPBOOK
+ record representing the entire own or external document with all referenced
+ sheets.
+ */
+class XclExpExternSheetBase : public XclExpRecord, protected XclExpRoot
+{
+public:
+ explicit XclExpExternSheetBase( const XclExpRoot& rRoot,
+ sal_uInt16 nRecId, sal_uInt32 nRecSize = 0 );
+
+protected:
+ /** Creates and returns the list of EXTERNNAME records. */
+ XclExpExtNameBuffer& GetExtNameBuffer();
+ /** Creates and returns the list of EXTERNNAME records. */
+ void WriteExtNameBuffer( XclExpStream& rStrm );
+
+private:
+ typedef ScfRef< XclExpExtNameBuffer > XclExpExtNameBfrRef;
+ XclExpExtNameBfrRef mxExtNameBfr; /// List of EXTERNNAME records.
+};
+
+// External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
+
+/** Represents an EXTERNSHEET record containing the URL and sheet name of a sheet.
+ @descr This class is used up to BIFF7 only, writing a BIFF8 EXTERNSHEET
+ record is implemented directly in the link manager. */
+class XclExpExternSheet : public XclExpExternSheetBase
+{
+public:
+ /** Creates an EXTERNSHEET record containing a special code (i.e. own document or sheet). */
+ explicit XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode );
+ /** Creates an EXTERNSHEET record referring to an internal sheet. */
+ explicit XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName );
+
+ /** Finds or inserts an EXTERNNAME record for add-ins.
+ @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+ sal_uInt16 InsertAddIn( const String& rName );
+
+ /** Writes the EXTERNSHEET and all EXTERNNAME, XCT and CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Initializes the record data with the passed encoded URL. */
+ void Init( const String& rEncUrl );
+ /** Writes the contents of the EXTERNSHEET record. */
+ virtual void WriteBody( XclExpStream& rStrm );
+
+private:
+ XclExpString maTabName; /// The name of the sheet.
+};
+
+// External documents (SUPBOOK, BIFF8) ========================================
+
+/** The SUPBOOK record contains data for an external document (URL, sheet names, external values). */
+class XclExpSupbook : public XclExpExternSheetBase
+{
+public:
+ /** Creates a SUPBOOK record for internal references. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount );
+ /** Creates a SUPBOOK record for add-in functions. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot );
+ /** EUROTOOL SUPBOOK */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType );
+ /** Creates a SUPBOOK record for an external document. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl );
+ /** Creates a SUPBOOK record for a DDE link. */
+ explicit XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic );
+
+ /** Returns true, if this SUPBOOK contains the passed URL of an external document. */
+ bool IsUrlLink( const String& rUrl ) const;
+ /** Returns true, if this SUPBOOK contains the passed DDE link. */
+ bool IsDdeLink( const String& rApplic, const String& rTopic ) const;
+ /** Fills the passed reference log entry with the URL and sheet names. */
+ void FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
+ sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const;
+
+ /** 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 ::formula::FormulaToken& rToken );
+ void StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ::formula::FormulaToken& 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, ScExternalRefCache::TableTypeRef xCacheTable );
+ /** Finds or inserts an EXTERNNAME record for add-ins.
+ @return The 1-based EXTERNNAME record index; or 0, if the record list is full. */
+ sal_uInt16 InsertAddIn( const String& rName );
+ /** InsertEuroTool */
+ sal_uInt16 InsertEuroTool( const String& rName );
+ /** Finds or inserts an EXTERNNAME record for DDE links.
+ @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 ScExternalRefCache::TokenArrayRef pArray );
+
+ /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Returns the sheet name inside of this SUPBOOK. */
+ const XclExpString* GetTabName( sal_uInt16 nSBTab ) const;
+
+ /** Writes the SUPBOOK record contents. */
+ virtual void WriteBody( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpXct > XclExpXctList;
+ typedef XclExpXctList::RecordRefType XclExpXctRef;
+
+ XclExpXctList maXctList; /// List of XCT records (which contain CRN records).
+ String maUrl; /// URL of the external document or application name for DDE.
+ String maDdeTopic; /// Topic of an DDE link.
+ XclExpString maUrlEncoded; /// Document name encoded for Excel.
+ XclSupbookType meType; /// Type of this SUPBOOK record.
+ sal_uInt16 mnXclTabCount; /// Number of internal sheets.
+};
+
+// All SUPBOOKS in a document =================================================
+
+/** This struct contains a sheet index range for 3D references.
+ @descr This reference consists of an index to a SUPBOOK record and indexes
+ to SUPBOOK sheet names. */
+struct XclExpXti
+{
+ sal_uInt16 mnSupbook; /// Index to SUPBOOK record.
+ sal_uInt16 mnFirstSBTab; /// Index to the first sheet of the range in the SUPBOOK.
+ sal_uInt16 mnLastSBTab; /// Index to the last sheet of the range in the SUPBOOK.
+
+ inline explicit XclExpXti() : mnSupbook( 0 ), mnFirstSBTab( 0 ), mnLastSBTab( 0 ) {}
+ inline explicit XclExpXti( sal_uInt16 nSupbook, sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) :
+ mnSupbook( nSupbook ), mnFirstSBTab( nFirstSBTab ), mnLastSBTab( nLastSBTab ) {}
+
+ /** Writes this XTI structure (inside of the EXTERNSHEET record). */
+ inline void Save( XclExpStream& rStrm ) const
+ { rStrm << mnSupbook << mnFirstSBTab << mnLastSBTab; }
+};
+
+inline bool operator==( const XclExpXti& rLeft, const XclExpXti& rRight )
+{
+ return
+ (rLeft.mnSupbook == rRight.mnSupbook) &&
+ (rLeft.mnFirstSBTab == rRight.mnFirstSBTab) &&
+ (rLeft.mnLastSBTab == rRight.mnLastSBTab);
+}
+
+// ----------------------------------------------------------------------------
+
+/** Contains a list of all SUPBOOK records and index arrays of external sheets. */
+class XclExpSupbookBuffer : public XclExpRecordBase, protected XclExpRoot
+{
+public:
+ explicit XclExpSupbookBuffer( const XclExpRoot& rRoot );
+
+ /** Finds SUPBOOK index and SUPBOOK sheet range from given Excel sheet range.
+ @return An XTI structure containing SUPBOOK and sheet indexes. */
+ XclExpXti GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
+ XclExpRefLogEntry* pRefLogEntry = 0 ) const;
+
+ /** 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. */
+ bool InsertAddIn(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rName );
+ /** InsertEuroTool */
+ bool InsertEuroTool(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rName );
+ /** Finds or inserts an EXTERNNAME record for DDE links.
+ @param rnSupbook Returns the index of the SUPBOOK record which contains the DDE link.
+ @param rnExtName Returns the 1-based EXTERNNAME record index. */
+ bool InsertDde(
+ 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 ScExternalRefCache::TokenArrayRef 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;
+
+private:
+ /** Searches for the SUPBOOK record containing the passed document URL.
+ @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
+ @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
+ @return True, if the SUPBOOK record exists (out-parameters are valid). */
+ bool GetSupbookUrl( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
+ const String& rUrl ) const;
+ /** Searches for the SUPBOOK record containing the passed DDE link.
+ @param rxSupbook (out-param) Returns a reference to the SUPBOOK record, or 0.
+ @param rnIndex (out-param) Returns the list index, if the SUPBOOK exists.
+ @return True, if the SUPBOOK record exists (out-parameters are valid). */
+ bool GetSupbookDde( XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex,
+ const String& rApplic, const String& rTopic ) const;
+
+ /** Appends a new SUPBOOK to the list.
+ @return The list index of the SUPBOOK record. */
+ sal_uInt16 Append( XclExpSupbookRef xSupbook );
+
+private:
+ 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.
+ sal_uInt16 mnAddInSB; /// Index to add-in SUPBOOK.
+};
+
+// Export link manager ========================================================
+
+/** Abstract base class for implementation classes of the link manager. */
+class XclExpLinkManagerImpl : protected XclExpRoot
+{
+public:
+ /** Derived classes search for an EXTSHEET structure for the given Calc sheet range. */
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ XclExpRefLogEntry* pRefLogEntry ) = 0;
+ /** 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 ScSingleRefData& rRef1, const ScSingleRefData& rRef2 ) = 0;
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) = 0;
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& 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,
+ const String& rName ) = 0;
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName ) = 0;
+
+ /** Derived classes find or insert an EXTERNNAME record for DDE links. */
+ virtual bool InsertDde(
+ 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 ScExternalRefCache::TokenArrayRef pArray ) = 0;
+
+ /** Derived classes write the entire link table to the passed stream. */
+ virtual void Save( XclExpStream& rStrm ) = 0;
+
+protected:
+ explicit XclExpLinkManagerImpl( const XclExpRoot& rRoot );
+};
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the link manager for BIFF5/BIFF7. */
+class XclExpLinkManagerImpl5 : public XclExpLinkManagerImpl
+{
+public:
+ explicit XclExpLinkManagerImpl5( const XclExpRoot& rRoot );
+
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ 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 ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual bool InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ 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 ScExternalRefCache::TokenArrayRef pArray );
+
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ typedef XclExpRecordList< XclExpExternSheet > XclExpExtSheetList;
+ typedef XclExpExtSheetList::RecordRefType XclExpExtSheetRef;
+ typedef ::std::map< SCTAB, sal_uInt16 > XclExpIntTabMap;
+ typedef ::std::map< sal_Unicode, sal_uInt16 > XclExpCodeMap;
+
+private:
+ /** Returns the number of EXTERNSHEET records. */
+ sal_uInt16 GetExtSheetCount() const;
+
+ /** Appends an internal EXTERNSHEET record and returns the one-based index. */
+ sal_uInt16 AppendInternal( XclExpExtSheetRef xExtSheet );
+ /** Creates all EXTERNSHEET records for internal sheets on first call. */
+ void CreateInternal();
+
+ /** Returns the specified internal EXTERNSHEET record. */
+ XclExpExtSheetRef GetInternal( sal_uInt16 nExtSheet );
+ /** Returns the EXTERNSHEET index of an internal Calc sheet, or a deleted reference. */
+ XclExpExtSheetRef FindInternal( sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab );
+ /** Finds or creates the EXTERNSHEET index of an internal special EXTERNSHEET. */
+ XclExpExtSheetRef FindInternal( sal_uInt16& rnExtSheet, sal_Unicode cCode );
+
+private:
+ XclExpExtSheetList maExtSheetList; /// List with EXTERNSHEET records.
+ XclExpIntTabMap maIntTabMap; /// Maps internal Calc sheets to EXTERNSHEET records.
+ XclExpCodeMap maCodeMap; /// Maps special external codes to EXTERNSHEET records.
+};
+
+// ----------------------------------------------------------------------------
+
+/** Implementation of the link manager for BIFF8. */
+class XclExpLinkManagerImpl8 : public XclExpLinkManagerImpl
+{
+public:
+ explicit XclExpLinkManagerImpl8( const XclExpRoot& rRoot );
+
+ virtual void FindExtSheet( sal_uInt16& rnExtSheet,
+ sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab,
+ 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 ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual void StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef );
+ virtual void StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& rRef2 );
+
+ virtual bool InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName );
+ /** InsertEuroTool */
+ virtual bool InsertEuroTool(
+ 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 ScExternalRefCache::TokenArrayRef pArray );
+
+ virtual void Save( XclExpStream& rStrm );
+
+private:
+ /** Searches for or inserts a new XTI structure.
+ @return The 0-based list index of the XTI structure. */
+ sal_uInt16 InsertXti( const XclExpXti& rXti );
+
+private:
+ typedef ::std::vector< XclExpXti > XclExpXtiVec;
+
+ XclExpSupbookBuffer maSBBuffer; /// List of all SUPBOOK records.
+ XclExpXtiVec maXtiVec; /// List of XTI structures for the EXTERNSHEET record.
+};
+
+// ============================================================================
+// *** Implementation ***
+// ============================================================================
+
+// Excel sheet indexes ========================================================
+
+const sal_uInt8 EXC_TABBUF_IGNORE = 0x01; /// Sheet will be ignored completely.
+const sal_uInt8 EXC_TABBUF_EXTERN = 0x02; /// Sheet is linked externally.
+const sal_uInt8 EXC_TABBUF_SKIPMASK = 0x0F; /// Sheet will be skipped, if any flag is set.
+const sal_uInt8 EXC_TABBUF_VISIBLE = 0x10; /// Sheet is visible.
+const sal_uInt8 EXC_TABBUF_SELECTED = 0x20; /// Sheet is selected.
+const sal_uInt8 EXC_TABBUF_MIRRORED = 0x40; /// Sheet is mirrored (right-to-left).
+
+// ----------------------------------------------------------------------------
+
+XclExpTabInfo::XclExpTabInfo( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnScCnt( 0 ),
+ mnXclCnt( 0 ),
+ mnXclExtCnt( 0 ),
+ mnXclSelCnt( 0 ),
+ mnDisplXclTab( 0 ),
+ mnFirstVisXclTab( 0 )
+{
+ ScDocument& rDoc = GetDoc();
+ ScExtDocOptions& rDocOpt = GetExtDocOptions();
+
+ mnScCnt = rDoc.GetTableCount();
+
+ SCTAB nScTab;
+ SCTAB nFirstVisScTab = SCTAB_INVALID; // first visible sheet
+ SCTAB nFirstExpScTab = SCTAB_INVALID; // first exported sheet
+
+ // --- initialize the flags in the index buffer ---
+
+ maTabInfoVec.resize( mnScCnt );
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ // ignored sheets (skipped by export, with invalid Excel sheet index)
+ if( rDoc.IsScenario( nScTab ) )
+ {
+ SetFlag( nScTab, EXC_TABBUF_IGNORE );
+ }
+
+ // external sheets (skipped, but with valid Excel sheet index for ref's)
+ else if( rDoc.GetLinkMode( nScTab ) == SC_LINK_VALUE )
+ {
+ SetFlag( nScTab, EXC_TABBUF_EXTERN );
+ }
+
+ // exported sheets
+ else
+ {
+ // sheet name
+ rDoc.GetName( nScTab, maTabInfoVec[ nScTab ].maScName );
+
+ // remember first exported sheet
+ if( nFirstExpScTab == SCTAB_INVALID )
+ nFirstExpScTab = nScTab;
+ // remember first visible exported sheet
+ if( (nFirstVisScTab == SCTAB_INVALID) && rDoc.IsVisible( nScTab ) )
+ nFirstVisScTab = nScTab;
+
+ // sheet visible (only exported sheets)
+ SetFlag( nScTab, EXC_TABBUF_VISIBLE, rDoc.IsVisible( nScTab ) );
+
+ // sheet selected (only exported sheets)
+ if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nScTab ) )
+ SetFlag( nScTab, EXC_TABBUF_SELECTED, pTabSett->mbSelected );
+
+ // sheet mirrored (only exported sheets)
+ SetFlag( nScTab, EXC_TABBUF_MIRRORED, rDoc.IsLayoutRTL( nScTab ) );
+ }
+ }
+
+ // --- visible/selected sheets ---
+
+ SCTAB nDisplScTab = rDocOpt.GetDocSettings().mnDisplTab;
+
+ // #112908# find first visible exported sheet
+ if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
+ {
+ // no exportable visible sheet -> use first exportable sheet
+ nFirstVisScTab = nFirstExpScTab;
+ if( (nFirstVisScTab == SCTAB_INVALID) || !IsExportTab( nFirstVisScTab ) )
+ {
+ // no exportable sheet at all -> use active sheet and export it
+ nFirstVisScTab = nDisplScTab;
+ SetFlag( nFirstVisScTab, EXC_TABBUF_SKIPMASK, false ); // clear skip flags
+ }
+ SetFlag( nFirstVisScTab, EXC_TABBUF_VISIBLE ); // must be visible, even if originally hidden
+ }
+
+ // find currently displayed sheet
+ if( !IsExportTab( nDisplScTab ) ) // selected sheet not exported (i.e. scenario) -> use first visible
+ nDisplScTab = nFirstVisScTab;
+ SetFlag( nDisplScTab, EXC_TABBUF_VISIBLE | EXC_TABBUF_SELECTED );
+
+ // number of selected sheets
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ if( IsSelectedTab( nScTab ) )
+ ++mnXclSelCnt;
+
+ // --- calculate resulting Excel sheet indexes ---
+
+ CalcXclIndexes();
+ mnFirstVisXclTab = GetXclTab( nFirstVisScTab );
+ mnDisplXclTab = GetXclTab( nDisplScTab );
+
+ // --- sorted vectors for index lookup ---
+
+ CalcSortedIndexes();
+}
+
+bool XclExpTabInfo::IsExportTab( SCTAB nScTab ) const
+{
+ /* Check sheet index before to avoid assertion in GetFlag(). */
+ return (nScTab < mnScCnt) && !GetFlag( nScTab, EXC_TABBUF_SKIPMASK );
+}
+
+bool XclExpTabInfo::IsExternalTab( SCTAB nScTab ) const
+{
+ /* Check sheet index before to avoid assertion (called from formula
+ compiler also for deleted references). */
+ return (nScTab < mnScCnt) && GetFlag( nScTab, EXC_TABBUF_EXTERN );
+}
+
+bool XclExpTabInfo::IsVisibleTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_VISIBLE );
+}
+
+bool XclExpTabInfo::IsSelectedTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_SELECTED );
+}
+
+bool XclExpTabInfo::IsDisplayedTab( SCTAB nScTab ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
+ return GetXclTab( nScTab ) == mnDisplXclTab;
+}
+
+bool XclExpTabInfo::IsMirroredTab( SCTAB nScTab ) const
+{
+ return GetFlag( nScTab, EXC_TABBUF_MIRRORED );
+}
+
+const String& XclExpTabInfo::GetScTabName( SCTAB nScTab ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::IsActiveTab - sheet out of range" );
+ return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].maScName : EMPTY_STRING;
+}
+
+sal_uInt16 XclExpTabInfo::GetXclTab( SCTAB nScTab ) const
+{
+ return (nScTab < mnScCnt) ? maTabInfoVec[ nScTab ].mnXclTab : EXC_TAB_DELETED;
+}
+
+SCTAB XclExpTabInfo::GetRealScTab( SCTAB nSortedScTab ) const
+{
+ DBG_ASSERT( nSortedScTab < mnScCnt, "XclExpTabInfo::GetRealScTab - sheet out of range" );
+ return (nSortedScTab < mnScCnt) ? maFromSortedVec[ nSortedScTab ] : SCTAB_INVALID;
+}
+
+//UNUSED2009-05 SCTAB XclExpTabInfo::GetSortedScTab( SCTAB nScTab ) const
+//UNUSED2009-05 {
+//UNUSED2009-05 DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::GetSortedScTab - sheet out of range" );
+//UNUSED2009-05 return (nScTab < mnScCnt) ? maToSortedVec[ nScTab ] : SCTAB_INVALID;
+//UNUSED2009-05 }
+
+bool XclExpTabInfo::GetFlag( SCTAB nScTab, sal_uInt8 nFlags ) const
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::GetFlag - sheet out of range" );
+ return (nScTab < mnScCnt) && ::get_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags );
+}
+
+void XclExpTabInfo::SetFlag( SCTAB nScTab, sal_uInt8 nFlags, bool bSet )
+{
+ DBG_ASSERT( nScTab < mnScCnt, "XclExpTabInfo::SetFlag - sheet out of range" );
+ if( nScTab < mnScCnt )
+ ::set_flag( maTabInfoVec[ nScTab ].mnFlags, nFlags, bSet );
+}
+
+void XclExpTabInfo::CalcXclIndexes()
+{
+ sal_uInt16 nXclTab = 0;
+ SCTAB nScTab = 0;
+
+ // --- pass 1: process regular sheets ---
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ if( IsExportTab( nScTab ) )
+ {
+ maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
+ ++nXclTab;
+ }
+ else
+ maTabInfoVec[ nScTab ].mnXclTab = EXC_TAB_DELETED;
+ }
+ mnXclCnt = nXclTab;
+
+ // --- pass 2: process external sheets (nXclTab continues) ---
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ if( IsExternalTab( nScTab ) )
+ {
+ maTabInfoVec[ nScTab ].mnXclTab = nXclTab;
+ ++nXclTab;
+ ++mnXclExtCnt;
+ }
+ }
+
+ // result: first occur all exported sheets, followed by all external sheets
+}
+
+typedef ::std::pair< String, SCTAB > XclExpTabName;
+typedef ::std::vector< XclExpTabName > XclExpTabNameVec;
+
+inline bool operator<( const XclExpTabName& rArg1, const XclExpTabName& rArg2 )
+{
+ // compare the sheet names only
+ return ScGlobal::GetCollator()->compareString( rArg1.first, rArg2.first ) == COMPARE_LESS;
+}
+
+void XclExpTabInfo::CalcSortedIndexes()
+{
+ ScDocument& rDoc = GetDoc();
+ XclExpTabNameVec aVec( mnScCnt );
+ SCTAB nScTab;
+
+ // fill with sheet names
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ rDoc.GetName( nScTab, aVec[ nScTab ].first );
+ aVec[ nScTab ].second = nScTab;
+ }
+ ::std::sort( aVec.begin(), aVec.end() );
+
+ // fill index vectors from sorted sheet name vector
+ maFromSortedVec.resize( mnScCnt );
+ maToSortedVec.resize( mnScCnt );
+ for( nScTab = 0; nScTab < mnScCnt; ++nScTab )
+ {
+ maFromSortedVec[ nScTab ] = aVec[ nScTab ].second;
+ maToSortedVec[ aVec[ nScTab ].second ] = nScTab;
+ }
+}
+
+// External names =============================================================
+
+XclExpExtNameBase::XclExpExtNameBase(
+ const XclExpRoot& rRoot, const String& rName, sal_uInt16 nFlags ) :
+ XclExpRecord( EXC_ID_EXTERNNAME ),
+ XclExpRoot( rRoot ),
+ maName( rName ),
+ mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ),
+ mnFlags( nFlags )
+{
+ DBG_ASSERT( maName.Len() <= 255, "XclExpExtNameBase::XclExpExtNameBase - string too long" );
+ SetRecSize( 6 + mxName->GetSize() );
+}
+
+XclExpExtNameBase::~XclExpExtNameBase()
+{
+}
+
+void XclExpExtNameBase::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << mnFlags
+ << sal_uInt32( 0 )
+ << *mxName;
+ WriteAddData( rStrm );
+}
+
+void XclExpExtNameBase::WriteAddData( XclExpStream& /*rStrm*/ )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtNameAddIn::XclExpExtNameAddIn( const XclExpRoot& rRoot, const String& rName ) :
+ XclExpExtNameBase( rRoot, rName )
+{
+ AddRecSize( 4 );
+}
+
+void XclExpExtNameAddIn::WriteAddData( XclExpStream& rStrm )
+{
+ // write a #REF! error formula
+ rStrm << sal_uInt16( 2 ) << EXC_TOKID_ERR << EXC_ERR_REF;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtNameDde::XclExpExtNameDde( const XclExpRoot& rRoot,
+ const String& rName, sal_uInt16 nFlags, const ScMatrix* pResults ) :
+ XclExpExtNameBase( rRoot, rName, nFlags )
+{
+ if( pResults )
+ {
+ mxMatrix.reset( new XclExpCachedMatrix( *pResults ) );
+ AddRecSize( mxMatrix->GetSize() );
+ }
+}
+
+void XclExpExtNameDde::WriteAddData( XclExpStream& rStrm )
+{
+ if( mxMatrix.is() )
+ mxMatrix->Save( rStrm );
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpExtName::XclExpExtName( const XclExpRoot& rRoot, const XclExpSupbook& rSupbook,
+ const String& rName, const ScExternalRefCache::TokenArrayRef 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.
+
+ using namespace ::formula;
+ do
+ {
+ if (mpArray->GetLen() != 1)
+ break;
+
+ const ScToken* p = static_cast<const ScToken*>(mpArray->First());
+ if (p->GetOpCode() != ocExternalRef)
+ break;
+
+ switch (p->GetType())
+ {
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rRef = p->GetSingleRef();
+ if (rRef.IsTabRel())
+ break;
+
+ bool bColRel = rRef.IsColRel();
+ bool bRowRel = rRef.IsRowRel();
+ sal_uInt16 nCol = static_cast< sal_uInt16 >( bColRel ? rRef.nRelCol : rRef.nCol );
+ sal_uInt16 nRow = static_cast< sal_uInt16 >( 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 svExternalDoubleRef:
+ {
+ const ScComplexRefData& rRef = p->GetDoubleRef();
+ const ScSingleRefData& r1 = rRef.Ref1;
+ const ScSingleRefData& 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 = static_cast< sal_uInt16 >( bCol1Rel ? r1.nRelCol : r1.nCol );
+ sal_uInt16 nCol2 = static_cast< sal_uInt16 >( bCol2Rel ? r2.nRelCol : r2.nCol );
+ sal_uInt16 nRow1 = static_cast< sal_uInt16 >( bRow1Rel ? r1.nRelRow : r1.nRow );
+ sal_uInt16 nRow2 = static_cast< sal_uInt16 >( 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;
+ }
+ default:
+ ; // nothing
+ }
+ }
+ 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 ) :
+ XclExpRoot( rRoot )
+{
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertAddIn( const String& rName )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtNameAddIn( GetRoot(), rName ) );
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertEuroTool( const String& rName )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtNameBase( GetRoot(), rName ) );
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertDde(
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ sal_uInt16 nIndex = GetIndex( rItem );
+ if( nIndex == 0 )
+ {
+ USHORT nPos;
+ if( GetDoc().FindDdeLink( rApplic, rTopic, rItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ // create the leading 'StdDocumentName' EXTERNNAME record
+ if( maNameList.IsEmpty() )
+ AppendNew( new XclExpExtNameDde(
+ GetRoot(), CREATE_STRING( "StdDocumentName" ), EXC_EXTN_EXPDDE_STDDOC ) );
+
+ // try to find DDE result array, but create EXTERNNAME record without them too
+ const ScMatrix* pScMatrix = GetDoc().GetDdeLinkResultMatrix( nPos );
+ nIndex = AppendNew( new XclExpExtNameDde( GetRoot(), rItem, EXC_EXTN_EXPDDE, pScMatrix ) );
+ }
+ }
+ return nIndex;
+}
+
+sal_uInt16 XclExpExtNameBuffer::InsertExtName( const XclExpSupbook& rSupbook,
+ const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ sal_uInt16 nIndex = GetIndex( rName );
+ return nIndex ? nIndex : AppendNew( new XclExpExtName( GetRoot(), rSupbook, rName, pArray ) );
+}
+
+void XclExpExtNameBuffer::Save( XclExpStream& rStrm )
+{
+ maNameList.Save( rStrm );
+}
+
+sal_uInt16 XclExpExtNameBuffer::GetIndex( const String& rName ) const
+{
+ for( size_t nPos = 0, nSize = maNameList.GetSize(); nPos < nSize; ++nPos )
+ if( maNameList.GetRecord( nPos )->GetName() == rName )
+ return static_cast< sal_uInt16 >( nPos + 1 );
+ return 0;
+}
+
+sal_uInt16 XclExpExtNameBuffer::AppendNew( XclExpExtNameBase* pExtName )
+{
+ XclExpExtNameRef xExtName( pExtName );
+ size_t nSize = maNameList.GetSize();
+ if( nSize < 0x7FFF )
+ {
+ maNameList.AppendRecord( xExtName );
+ return static_cast< sal_uInt16 >( nSize + 1 );
+ }
+ return 0;
+}
+
+// Cached external cells ======================================================
+
+XclExpCrn::XclExpCrn( SCCOL nScCol, SCROW nScRow, const Any& rValue ) :
+ XclExpRecord( EXC_ID_CRN, 4 ),
+ mnScCol( nScCol ),
+ mnScRow( nScRow )
+{
+ maValues.push_back( rValue );
+}
+
+bool XclExpCrn::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
+{
+ if( (nScRow != mnScRow) || (nScCol != static_cast< SCCOL >( mnScCol + maValues.size() )) )
+ return false;
+ maValues.push_back( rValue );
+ return true;
+}
+
+void XclExpCrn::WriteBody( XclExpStream& rStrm )
+{
+ rStrm << static_cast< sal_uInt8 >( mnScCol + maValues.size() - 1 )
+ << static_cast< sal_uInt8 >( mnScCol )
+ << static_cast< sal_uInt16 >( mnScRow );
+ for( CachedValues::iterator aIt = maValues.begin(), aEnd = maValues.end(); aIt != aEnd; ++aIt )
+ {
+ if( aIt->has< bool >() )
+ WriteBool( rStrm, aIt->get< bool >() );
+ else if( aIt->has< double >() )
+ WriteDouble( rStrm, aIt->get< double >() );
+ else if( aIt->has< OUString >() )
+ WriteString( rStrm, aIt->get< OUString >() );
+ else
+ WriteEmpty( rStrm );
+ }
+}
+
+void XclExpCrn::WriteBool( XclExpStream& rStrm, bool bValue )
+{
+ rStrm << EXC_CACHEDVAL_BOOL << sal_uInt8( bValue ? 1 : 0);
+ rStrm.WriteZeroBytes( 7 );
+}
+
+void XclExpCrn::WriteDouble( XclExpStream& rStrm, double fValue )
+{
+ if( ::rtl::math::isNan( fValue ) )
+ {
+ USHORT nScError = static_cast< USHORT >( reinterpret_cast< const sal_math_Double* >( &fValue )->nan_parts.fraction_lo );
+ WriteError( rStrm, XclTools::GetXclErrorCode( nScError ) );
+ }
+ else
+ {
+ rStrm << EXC_CACHEDVAL_DOUBLE << fValue;
+ }
+}
+
+void XclExpCrn::WriteString( XclExpStream& rStrm, const OUString& rValue )
+{
+ rStrm << EXC_CACHEDVAL_STRING << XclExpString( rValue );
+}
+
+void XclExpCrn::WriteError( XclExpStream& rStrm, sal_uInt8 nErrCode )
+{
+ rStrm << EXC_CACHEDVAL_ERROR << nErrCode;
+ rStrm.WriteZeroBytes( 7 );
+}
+
+void XclExpCrn::WriteEmpty( XclExpStream& rStrm )
+{
+ rStrm << EXC_CACHEDVAL_EMPTY;
+ rStrm.WriteZeroBytes( 8 );
+}
+
+// Cached cells of a sheet ====================================================
+
+XclExpXct::XclExpXct( const XclExpRoot& rRoot, const String& rTabName,
+ sal_uInt16 nSBTab, ScExternalRefCache::TableTypeRef xCacheTable ) :
+ XclExpRoot( rRoot ),
+ mxCacheTable( xCacheTable ),
+ maBoundRange( ScAddress::INITIALIZE_INVALID ),
+ maTabName( rTabName ),
+ mnSBTab( nSBTab )
+{
+}
+
+void XclExpXct::StoreCellRange( const ScRange& rRange )
+{
+ // #i70418# restrict size of external range to prevent memory overflow
+ if( (rRange.aEnd.Col() - rRange.aStart.Col()) * (rRange.aEnd.Row() - rRange.aStart.Row()) > 1024 )
+ return;
+
+ maUsedCells.SetMultiMarkArea( rRange );
+ maBoundRange.ExtendTo( rRange );
+}
+
+void XclExpXct::StoreCell( const ScAddress& rCell, const ::formula::FormulaToken& rToken )
+{
+ maUsedCells.SetMultiMarkArea( ScRange( rCell ) );
+ maBoundRange.ExtendTo( ScRange( rCell ) );
+ (void)rToken;
+}
+
+void XclExpXct::StoreCellRange( const ScRange& rRange, const ::formula::FormulaToken& rToken )
+{
+ maUsedCells.SetMultiMarkArea( rRange );
+ maBoundRange.ExtendTo( rRange );
+ (void)rToken;
+}
+
+namespace {
+
+class XclExpCrnList : public XclExpRecordList< XclExpCrn >
+{
+public:
+ /** Inserts the passed value into an existing or new CRN record.
+ @return True = value inserted successfully, false = CRN list is full. */
+ bool InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue );
+};
+
+bool XclExpCrnList::InsertValue( SCCOL nScCol, SCROW nScRow, const Any& rValue )
+{
+ RecordRefType xLastRec = GetLastRecord();
+ if( xLastRec.is() && xLastRec->InsertValue( nScCol, nScRow, rValue ) )
+ return true;
+ if( GetSize() == SAL_MAX_UINT16 )
+ return false;
+ AppendNewRecord( new XclExpCrn( nScCol, nScRow, rValue ) );
+ return true;
+}
+
+} // namespace
+
+void XclExpXct::Save( XclExpStream& rStrm )
+{
+ if( !mxCacheTable )
+ return;
+
+ /* Get the range of used rows in the cache table. This may help to
+ optimize building the CRN record list if the cache table does not
+ contain all referred cells, e.g. if big empty ranges are used in the
+ formulas. */
+ ::std::pair< SCROW, SCROW > aRowRange = mxCacheTable->getRowRange();
+ if( aRowRange.first >= aRowRange.second )
+ return;
+
+ /* Crop the bounding range of used cells in this table to Excel limits.
+ Return if there is no external cell inside these limits. */
+ if( !GetAddressConverter().ValidateRange( maBoundRange, false ) )
+ return;
+
+ /* Find the resulting row range that needs to be processed. */
+ SCROW nScRow1 = ::std::max( aRowRange.first, maBoundRange.aStart.Row() );
+ SCROW nScRow2 = ::std::min( aRowRange.second - 1, maBoundRange.aEnd.Row() );
+ if( nScRow1 > nScRow2 )
+ return;
+
+ /* Build and collect all CRN records before writing the XCT record. This
+ is needed to determine the total number of CRN records which must be
+ known when writing the XCT record (possibly encrypted, so seeking the
+ output strem back after writing the CRN records is not an option). */
+ XclExpCrnList aCrnRecs;
+ SvNumberFormatter& rFormatter = GetFormatter();
+ bool bValid = true;
+ for( SCROW nScRow = nScRow1; bValid && (nScRow <= nScRow2); ++nScRow )
+ {
+ ::std::pair< SCCOL, SCCOL > aColRange = mxCacheTable->getColRange( nScRow );
+ for( SCCOL nScCol = aColRange.first; bValid && (nScCol < aColRange.second); ++nScCol )
+ {
+ if( maUsedCells.IsCellMarked( nScCol, nScRow, TRUE ) )
+ {
+ sal_uInt32 nScNumFmt = 0;
+ ScExternalRefCache::TokenRef xToken = mxCacheTable->getCell( nScCol, nScRow, &nScNumFmt );
+ using namespace ::formula;
+ if( xToken.get() ) switch( xToken->GetType() )
+ {
+ case svDouble:
+ bValid = (rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL) ?
+ aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() != 0 ) ) :
+ aCrnRecs.InsertValue( nScCol, nScRow, Any( xToken->GetDouble() ) );
+ break;
+ case svString:
+ // do not save empty strings (empty cells) to cache
+ if( xToken->GetString().Len() > 0 )
+ bValid = aCrnRecs.InsertValue( nScCol, nScRow, Any( OUString( xToken->GetString() ) ) );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // write the XCT record and the list of CRN records
+ rStrm.StartRecord( EXC_ID_XCT, 4 );
+ rStrm << static_cast< sal_uInt16 >( aCrnRecs.GetSize() ) << mnSBTab;
+ rStrm.EndRecord();
+ aCrnRecs.Save( rStrm );
+}
+
+// External documents (EXTERNSHEET/SUPBOOK), base class =======================
+
+XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot& rRoot, sal_uInt16 nRecId, sal_uInt32 nRecSize ) :
+ XclExpRecord( nRecId, nRecSize ),
+ XclExpRoot( rRoot )
+{
+}
+
+XclExpExtNameBuffer& XclExpExternSheetBase::GetExtNameBuffer()
+{
+ if( !mxExtNameBfr )
+ mxExtNameBfr.reset( new XclExpExtNameBuffer( GetRoot() ) );
+ return *mxExtNameBfr;
+}
+
+void XclExpExternSheetBase::WriteExtNameBuffer( XclExpStream& rStrm )
+{
+ if( mxExtNameBfr.is() )
+ mxExtNameBfr->Save( rStrm );
+}
+
+// External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
+
+XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode cCode ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
+{
+ Init( String( cCode ) );
+}
+
+XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, const String& rTabName ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_EXTERNSHEET )
+{
+ // reference to own sheet: \03<sheetname>
+ Init( String( EXC_EXTSH_TABNAME ).Append( rTabName ) );
+}
+
+void XclExpExternSheet::Save( XclExpStream& rStrm )
+{
+ // EXTERNSHEET record
+ XclExpRecord::Save( rStrm );
+ // EXTERNNAME records
+ WriteExtNameBuffer( rStrm );
+}
+
+void XclExpExternSheet::Init( const String& rEncUrl )
+{
+ DBG_ASSERT_BIFF( GetBiff() <= EXC_BIFF5 );
+ maTabName.AssignByte( rEncUrl, GetTextEncoding(), EXC_STR_8BITLENGTH );
+ SetRecSize( maTabName.GetSize() );
+}
+
+sal_uInt16 XclExpExternSheet::InsertAddIn( const String& rName )
+{
+ return GetExtNameBuffer().InsertAddIn( rName );
+}
+
+void XclExpExternSheet::WriteBody( XclExpStream& rStrm )
+{
+ sal_uInt8 nNameSize = static_cast< sal_uInt8 >( maTabName.Len() );
+ // special case: reference to own sheet (starting with '\03') needs wrong string length
+ if( maTabName.GetChar( 0 ) == EXC_EXTSH_TABNAME )
+ --nNameSize;
+ rStrm << nNameSize;
+ maTabName.WriteBuffer( rStrm );
+}
+
+// External document (SUPBOOK, BIFF8) =========================================
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ meType( EXC_SBTYPE_SELF ),
+ mnXclTabCount( nXclTabCount )
+{
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ meType( EXC_SBTYPE_ADDIN ),
+ mnXclTabCount( 1 )
+{
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl, XclSupbookType ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
+ maUrl( rUrl ),
+ maUrlEncoded( rUrl ),
+ meType( EXC_SBTYPE_EUROTOOL ),
+ mnXclTabCount( 0 )
+{
+ SetRecSize( 2 + maUrlEncoded.GetSize() );
+}
+
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rUrl ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK ),
+ maUrl( rUrl ),
+ maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot, rUrl ) ),
+ meType( EXC_SBTYPE_EXTERN ),
+ 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 );
+ ScfStringVec aTabNames;
+ pRefMgr->getAllCachedTableNames( nFileId, aTabNames );
+ for( ScfStringVec::const_iterator aBeg = aTabNames.begin(), aIt = aBeg, aEnd = aTabNames.end(); aIt != aEnd; ++aIt )
+ InsertTabName( *aIt, pRefMgr->getCacheTable( nFileId, aIt - aBeg ) );
+}
+
+XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, const String& rApplic, const String& rTopic ) :
+ XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
+ maUrl( rApplic ),
+ maDdeTopic( rTopic ),
+ maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic, rTopic ) ),
+ meType( EXC_SBTYPE_SPECIAL ),
+ mnXclTabCount( 0 )
+{
+ SetRecSize( 2 + maUrlEncoded.GetSize() );
+}
+
+bool XclExpSupbook::IsUrlLink( const String& rUrl ) const
+{
+ return (meType == EXC_SBTYPE_EXTERN || meType == EXC_SBTYPE_EUROTOOL) && (maUrl == rUrl);
+}
+
+bool XclExpSupbook::IsDdeLink( const String& rApplic, const String& rTopic ) const
+{
+ return (meType == EXC_SBTYPE_SPECIAL) && (maUrl == rApplic) && (maDdeTopic == rTopic);
+}
+
+void XclExpSupbook::FillRefLogEntry( XclExpRefLogEntry& rRefLogEntry,
+ sal_uInt16 nFirstSBTab, sal_uInt16 nLastSBTab ) const
+{
+ rRefLogEntry.mpUrl = maUrlEncoded.IsEmpty() ? 0 : &maUrlEncoded;
+ rRefLogEntry.mpFirstTab = GetTabName( nFirstSBTab );
+ rRefLogEntry.mpLastTab = GetTabName( nLastSBTab );
+}
+
+void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+{
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCellRange( rRange );
+}
+
+void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const formula::FormulaToken& rToken )
+{
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCell( rCell, rToken );
+}
+
+void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const formula::FormulaToken& rToken )
+{
+ // multi-table range is not allowed!
+ if( rRange.aStart.Tab() == rRange.aEnd.Tab() )
+ if( XclExpXct* pXct = maXctList.GetRecord( nSBTab ).get() )
+ pXct->StoreCellRange( 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, ScExternalRefCache::TableTypeRef xCacheTable )
+{
+ DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
+ sal_uInt16 nSBTab = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
+ XclExpXctRef xXct( new XclExpXct( GetRoot(), rTabName, nSBTab, xCacheTable ) );
+ AddRecSize( xXct->GetTabName().GetSize() );
+ maXctList.AppendRecord( xXct );
+ return nSBTab;
+}
+
+sal_uInt16 XclExpSupbook::InsertAddIn( const String& rName )
+{
+ return GetExtNameBuffer().InsertAddIn( rName );
+}
+
+sal_uInt16 XclExpSupbook::InsertEuroTool( const String& rName )
+{
+ return GetExtNameBuffer().InsertEuroTool( rName );
+}
+
+sal_uInt16 XclExpSupbook::InsertDde( const String& rItem )
+{
+ return GetExtNameBuffer().InsertDde( maUrl, maDdeTopic, rItem );
+}
+
+sal_uInt16 XclExpSupbook::InsertExtName( const String& rName, const ScExternalRefCache::TokenArrayRef pArray )
+{
+ return GetExtNameBuffer().InsertExtName(*this, rName, pArray);
+}
+
+void XclExpSupbook::Save( XclExpStream& rStrm )
+{
+ // SUPBOOK record
+ XclExpRecord::Save( rStrm );
+ // XCT record, CRN records
+ maXctList.Save( rStrm );
+ // EXTERNNAME records
+ WriteExtNameBuffer( rStrm );
+}
+
+const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
+{
+ XclExpXctRef xXct = maXctList.GetRecord( nSBTab );
+ return xXct.is() ? &xXct->GetTabName() : 0;
+}
+
+void XclExpSupbook::WriteBody( XclExpStream& rStrm )
+{
+ switch( meType )
+ {
+ case EXC_SBTYPE_SELF:
+ rStrm << mnXclTabCount << EXC_SUPB_SELF;
+ break;
+ case EXC_SBTYPE_EXTERN:
+ case EXC_SBTYPE_SPECIAL:
+ case EXC_SBTYPE_EUROTOOL:
+ {
+ sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
+ rStrm << nCount << maUrlEncoded;
+
+ for( size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos )
+ rStrm << maXctList.GetRecord( nPos )->GetTabName();
+ }
+ break;
+ case EXC_SBTYPE_ADDIN:
+ rStrm << mnXclTabCount << EXC_SUPB_ADDIN;
+ break;
+ default:
+ DBG_ERRORFILE( "XclExpSupbook::WriteBody - unknown SUPBOOK type" );
+ }
+}
+
+// All SUPBOOKS in a document =================================================
+
+XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot ),
+ mnOwnDocSB( SAL_MAX_UINT16 ),
+ mnAddInSB( SAL_MAX_UINT16 )
+{
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ sal_uInt16 nXclCnt = rTabInfo.GetXclTabCount();
+ sal_uInt16 nCodeCnt = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
+ size_t nCount = nXclCnt + rTabInfo.GetXclExtTabCount();
+
+ DBG_ASSERT( nCount > 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
+ if( nCount )
+ {
+ maSBIndexVec.resize( nCount );
+
+ // self-ref SUPBOOK first of list
+ XclExpSupbookRef xSupbook( new XclExpSupbook( GetRoot(), ::std::max( nXclCnt, nCodeCnt ) ) );
+ mnOwnDocSB = Append( xSupbook );
+ for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
+ maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
+ }
+}
+
+XclExpXti XclExpSupbookBuffer::GetXti( sal_uInt16 nFirstXclTab, sal_uInt16 nLastXclTab,
+ XclExpRefLogEntry* pRefLogEntry ) const
+{
+ XclExpXti aXti;
+ size_t nSize = maSBIndexVec.size();
+ if( (nFirstXclTab < nSize) && (nLastXclTab < nSize) )
+ {
+ // index of the SUPBOOK record
+ aXti.mnSupbook = maSBIndexVec[ nFirstXclTab ].mnSupbook;
+
+ // all sheets in the same supbook?
+ bool bSameSB = true;
+ for( sal_uInt16 nXclTab = nFirstXclTab + 1; bSameSB && (nXclTab <= nLastXclTab); ++nXclTab )
+ {
+ bSameSB = maSBIndexVec[ nXclTab ].mnSupbook == aXti.mnSupbook;
+ if( !bSameSB )
+ nLastXclTab = nXclTab - 1;
+ }
+ aXti.mnFirstSBTab = maSBIndexVec[ nFirstXclTab ].mnSBTab;
+ aXti.mnLastSBTab = maSBIndexVec[ nLastXclTab ].mnSBTab;
+
+ // fill external reference log entry (for change tracking)
+ if( pRefLogEntry )
+ {
+ pRefLogEntry->mnFirstXclTab = nFirstXclTab;
+ pRefLogEntry->mnLastXclTab = nLastXclTab;
+ XclExpSupbookRef xSupbook = maSupbookList.GetRecord( aXti.mnSupbook );
+ if( xSupbook.is() )
+ xSupbook->FillRefLogEntry( *pRefLogEntry, aXti.mnFirstSBTab, aXti.mnLastSBTab );
+ }
+ }
+ else
+ {
+ // special range, i.e. for deleted sheets or add-ins
+ aXti.mnSupbook = mnOwnDocSB;
+ aXti.mnFirstSBTab = nFirstXclTab;
+ aXti.mnLastSBTab = nLastXclTab;
+ }
+
+ return aXti;
+}
+
+void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+{
+ sal_uInt16 nXclTab = GetTabInfo().GetXclTab( rRange.aStart.Tab() );
+ if( nXclTab < maSBIndexVec.size() )
+ {
+ const XclExpSBIndex& rSBIndex = maSBIndexVec[ nXclTab ];
+ XclExpSupbookRef xSupbook = maSupbookList.GetRecord( rSBIndex.mnSupbook );
+ DBG_ASSERT( xSupbook.is(), "XclExpSupbookBuffer::StoreCellRange - missing SUPBOOK record" );
+ if( xSupbook.is() )
+ xSupbook->StoreCellRange( rRange, rSBIndex.mnSBTab );
+ }
+}
+
+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);
+ }
+
+ ScExternalRefCache::TokenRef pToken = pRefMgr->getSingleRefToken(nFileId, rTabName, rCell, NULL, NULL);
+ if (!pToken.get())
+ 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.
+ using namespace ::formula;
+ vector<FormulaToken*> aMatrixList;
+ aMatrixList.reserve(nTabCount);
+
+ // This is a new'ed instance, so we must manage its life cycle here.
+ ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, rRange, NULL);
+ if (!pArray.get())
+ return;
+
+ for (FormulaToken* 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 )
+{
+ XclExpSupbookRef xSupbook;
+ if( mnAddInSB == SAL_MAX_UINT16 )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot() ) );
+ mnAddInSB = Append( xSupbook );
+ }
+ else
+ xSupbook = maSupbookList.GetRecord( mnAddInSB );
+ DBG_ASSERT( xSupbook.is(), "XclExpSupbookBuffer::InsertAddin - missing add-in supbook" );
+ rnSupbook = mnAddInSB;
+ rnExtName = xSupbook->InsertAddIn( rName );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertEuroTool(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
+{
+ XclExpSupbookRef xSupbook;
+ String aUrl( RTL_CONSTASCII_USTRINGPARAM("\001\010EUROTOOL.XLA"));
+ if( !GetSupbookUrl( xSupbook, rnSupbook, aUrl ) )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot(), aUrl, EXC_SBTYPE_EUROTOOL ) );
+ rnSupbook = Append( xSupbook );
+ }
+ rnExtName = xSupbook->InsertEuroTool( rName );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertDde(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ XclExpSupbookRef xSupbook;
+ if( !GetSupbookDde( xSupbook, rnSupbook, rApplic, rTopic ) )
+ {
+ xSupbook.reset( new XclExpSupbook( GetRoot(), rApplic, rTopic ) );
+ rnSupbook = Append( xSupbook );
+ }
+ rnExtName = xSupbook->InsertDde( rItem );
+ return rnExtName > 0;
+}
+
+bool XclExpSupbookBuffer::InsertExtName(
+ sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rUrl,
+ const String& rName, const ScExternalRefCache::TokenArrayRef 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 );
+}
+
+bool XclExpSupbookBuffer::GetSupbookUrl(
+ XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex, const String& rUrl ) const
+{
+ for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
+ {
+ rxSupbook = maSupbookList.GetRecord( nPos );
+ if( rxSupbook->IsUrlLink( rUrl ) )
+ {
+ rnIndex = ulimit_cast< sal_uInt16 >( nPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+bool XclExpSupbookBuffer::GetSupbookDde( XclExpSupbookRef& rxSupbook,
+ sal_uInt16& rnIndex, const String& rApplic, const String& rTopic ) const
+{
+ for( size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; ++nPos )
+ {
+ rxSupbook = maSupbookList.GetRecord( nPos );
+ if( rxSupbook->IsDdeLink( rApplic, rTopic ) )
+ {
+ rnIndex = ulimit_cast< sal_uInt16 >( nPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
+{
+ maSupbookList.AppendRecord( xSupbook );
+ return ulimit_cast< sal_uInt16 >( maSupbookList.GetSize() - 1 );
+}
+
+// Export link manager ========================================================
+
+XclExpLinkManagerImpl::XclExpLinkManagerImpl( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpLinkManagerImpl5::XclExpLinkManagerImpl5( const XclExpRoot& rRoot ) :
+ XclExpLinkManagerImpl( rRoot )
+{
+}
+
+void XclExpLinkManagerImpl5::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ FindInternal( rnExtSheet, rnFirstXclTab, nFirstScTab );
+ if( (rnFirstXclTab == EXC_TAB_DELETED) || (nFirstScTab == nLastScTab) )
+ {
+ rnLastXclTab = rnFirstXclTab;
+ }
+ else
+ {
+ sal_uInt16 nDummyExtSheet;
+ FindInternal( nDummyExtSheet, rnLastXclTab, nLastScTab );
+ }
+
+ (void)pRefLogEntry; // avoid compiler warning
+ DBG_ASSERT( !pRefLogEntry, "XclExpLinkManagerImpl5::FindExtSheet - fill reflog entry not implemented" );
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::FindExtSheet( sal_Unicode cCode )
+{
+ sal_uInt16 nExtSheet;
+ FindInternal( nExtSheet, 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 ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
+{
+ // not implemented
+}
+
+void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef*/ )
+{
+ // not implemented
+}
+
+void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const String& /*rTabName*/, const ScSingleRefData& /*rRef1*/, const ScSingleRefData& /*rRef2*/ )
+{
+ // not implemented
+}
+
+bool XclExpLinkManagerImpl5::InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ XclExpExtSheetRef xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_ADDIN );
+ if( xExtSheet.is() )
+ {
+ rnExtName = xExtSheet->InsertAddIn( rName );
+ return rnExtName > 0;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl5::InsertEuroTool(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rName*/ )
+{
+ return false;
+}
+
+
+bool XclExpLinkManagerImpl5::InsertDde(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/,
+ const String& /*rApplic*/, const String& /*rTopic*/, const String& /*rItem*/ )
+{
+ // not implemented
+ return false;
+}
+
+bool XclExpLinkManagerImpl5::InsertExtName(
+ sal_uInt16& /*rnExtSheet*/, sal_uInt16& /*rnExtName*/, const String& /*rUrl*/,
+ const String& /*rName*/, const ScExternalRefCache::TokenArrayRef /*pArray*/ )
+{
+ // not implemented
+ return false;
+}
+
+void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
+{
+ if( sal_uInt16 nExtSheetCount = GetExtSheetCount() )
+ {
+ // EXTERNCOUNT record
+ XclExpUInt16Record( EXC_ID_EXTERNCOUNT, nExtSheetCount ).Save( rStrm );
+ // list of EXTERNSHEET records with EXTERNNAME, XCT, CRN records
+ maExtSheetList.Save( rStrm );
+ }
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::GetExtSheetCount() const
+{
+ return static_cast< sal_uInt16 >( maExtSheetList.GetSize() );
+}
+
+sal_uInt16 XclExpLinkManagerImpl5::AppendInternal( XclExpExtSheetRef xExtSheet )
+{
+ if( GetExtSheetCount() < 0x7FFF )
+ {
+ maExtSheetList.AppendRecord( xExtSheet );
+ // return negated one-based EXTERNSHEET index (i.e. 0xFFFD for 3rd record)
+ return static_cast< sal_uInt16 >( -GetExtSheetCount() );
+ }
+ return 0;
+}
+
+void XclExpLinkManagerImpl5::CreateInternal()
+{
+ if( maIntTabMap.empty() )
+ {
+ // create EXTERNSHEET records for all internal exported sheets
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
+ {
+ if( rTabInfo.IsExportTab( nScTab ) )
+ {
+ XclExpExtSheetRef xRec;
+ if( nScTab == GetCurrScTab() )
+ xRec.reset( new XclExpExternSheet( GetRoot(), EXC_EXTSH_OWNTAB ) );
+ else
+ xRec.reset( new XclExpExternSheet( GetRoot(), rTabInfo.GetScTabName( nScTab ) ) );
+ maIntTabMap[ nScTab ] = AppendInternal( xRec );
+ }
+ }
+ }
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::GetInternal( sal_uInt16 nExtSheet )
+{
+ return maExtSheetList.GetRecord( static_cast< sal_uInt16 >( -nExtSheet - 1 ) );
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab, SCTAB nScTab )
+{
+ // create internal EXTERNSHEET records on demand
+ CreateInternal();
+
+ // try to find an EXTERNSHEET record - if not, return a "deleted sheet" reference
+ XclExpExtSheetRef xExtSheet;
+ XclExpIntTabMap::const_iterator aIt = maIntTabMap.find( nScTab );
+ if( aIt == maIntTabMap.end() )
+ {
+ xExtSheet = FindInternal( rnExtSheet, EXC_EXTSH_OWNDOC );
+ rnXclTab = EXC_TAB_DELETED;
+ }
+ else
+ {
+ rnExtSheet = aIt->second;
+ xExtSheet = GetInternal( rnExtSheet );
+ rnXclTab = GetTabInfo().GetXclTab( nScTab );
+ }
+ return xExtSheet;
+}
+
+XclExpLinkManagerImpl5::XclExpExtSheetRef XclExpLinkManagerImpl5::FindInternal(
+ sal_uInt16& rnExtSheet, sal_Unicode cCode )
+{
+ XclExpExtSheetRef xExtSheet;
+ XclExpCodeMap::const_iterator aIt = maCodeMap.find( cCode );
+ if( aIt == maCodeMap.end() )
+ {
+ xExtSheet.reset( new XclExpExternSheet( GetRoot(), cCode ) );
+ rnExtSheet = maCodeMap[ cCode ] = AppendInternal( xExtSheet );
+ }
+ else
+ {
+ rnExtSheet = aIt->second;
+ xExtSheet = GetInternal( rnExtSheet );
+ }
+ return xExtSheet;
+}
+
+// ----------------------------------------------------------------------------
+
+XclExpLinkManagerImpl8::XclExpLinkManagerImpl8( const XclExpRoot& rRoot ) :
+ XclExpLinkManagerImpl( rRoot ),
+ maSBBuffer( rRoot )
+{
+}
+
+void XclExpLinkManagerImpl8::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ XclExpTabInfo& rTabInfo = GetTabInfo();
+ rnFirstXclTab = rTabInfo.GetXclTab( nFirstScTab );
+ rnLastXclTab = rTabInfo.GetXclTab( nLastScTab );
+ rnExtSheet = InsertXti( maSBBuffer.GetXti( rnFirstXclTab, rnLastXclTab, pRefLogEntry ) );
+}
+
+sal_uInt16 XclExpLinkManagerImpl8::FindExtSheet( sal_Unicode cCode )
+{
+ (void)cCode; // avoid compiler warning
+ DBG_ASSERT( (cCode == EXC_EXTSH_OWNDOC) || (cCode == EXC_EXTSH_ADDIN),
+ "XclExpLinkManagerImpl8::FindExtSheet - unknown externsheet code" );
+ 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 ScSingleRefData& rRef1, const ScSingleRefData& rRef2 )
+{
+ if( !rRef1.IsDeleted() && !rRef2.IsDeleted() && (rRef1.nTab >= 0) && (rRef2.nTab >= 0) )
+ {
+ const XclExpTabInfo& rTabInfo = GetTabInfo();
+ SCTAB nFirstScTab = static_cast< SCTAB >( rRef1.nTab );
+ SCTAB nLastScTab = static_cast< SCTAB >( rRef2.nTab );
+ ScRange aRange(
+ static_cast< SCCOL >( rRef1.nCol ), static_cast< SCROW >( rRef1.nRow ), 0,
+ static_cast< SCCOL >( rRef2.nCol ), static_cast< SCROW >( rRef2.nRow ), 0 );
+ for( SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab )
+ {
+ if( rTabInfo.IsExternalTab( nScTab ) )
+ {
+ aRange.aStart.SetTab( nScTab );
+ aRange.aEnd.SetTab( nScTab );
+ maSBBuffer.StoreCellRange( aRange );
+ }
+ }
+ }
+}
+
+void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
+ maSBBuffer.StoreCell(nFileId, rTabName, aAddr);
+}
+
+void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef1, const ScSingleRefData& 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 )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertAddIn( nSupbook, rnExtName, rName ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl8::InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertEuroTool( nSupbook, rnExtName, rName ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+
+bool XclExpLinkManagerImpl8::InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ sal_uInt16 nSupbook;
+ if( maSBBuffer.InsertDde( nSupbook, rnExtName, rApplic, rTopic, rItem ) )
+ {
+ rnExtSheet = InsertXti( XclExpXti( nSupbook, EXC_TAB_EXTERNAL, EXC_TAB_EXTERNAL ) );
+ return true;
+ }
+ return false;
+}
+
+bool XclExpLinkManagerImpl8::InsertExtName( sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rName, const String& rUrl, const ScExternalRefCache::TokenArrayRef 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() )
+ {
+ // SUPBOOKs, XCTs, CRNs, EXTERNNAMEs
+ maSBBuffer.Save( rStrm );
+
+ // EXTERNSHEET
+ sal_uInt16 nCount = ulimit_cast< sal_uInt16 >( maXtiVec.size() );
+ rStrm.StartRecord( EXC_ID_EXTERNSHEET, 2 + 6 * nCount );
+ rStrm << nCount;
+ rStrm.SetSliceSize( 6 );
+ for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
+ aIt->Save( rStrm );
+ rStrm.EndRecord();
+ }
+}
+
+sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
+{
+ for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
+ if( *aIt == rXti )
+ return ulimit_cast< sal_uInt16 >( aIt - maXtiVec.begin() );
+ maXtiVec.push_back( rXti );
+ return ulimit_cast< sal_uInt16 >( maXtiVec.size() - 1 );
+}
+
+// ============================================================================
+
+XclExpLinkManager::XclExpLinkManager( const XclExpRoot& rRoot ) :
+ XclExpRoot( rRoot )
+{
+ switch( GetBiff() )
+ {
+ case EXC_BIFF5:
+ mxImpl.reset( new XclExpLinkManagerImpl5( rRoot ) );
+ break;
+ case EXC_BIFF8:
+ mxImpl.reset( new XclExpLinkManagerImpl8( rRoot ) );
+ break;
+ default:
+ DBG_ERROR_BIFF();
+ }
+}
+
+XclExpLinkManager::~XclExpLinkManager()
+{
+}
+
+void XclExpLinkManager::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnXclTab,
+ SCTAB nScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ mxImpl->FindExtSheet( rnExtSheet, rnXclTab, rnXclTab, nScTab, nScTab, pRefLogEntry );
+}
+
+void XclExpLinkManager::FindExtSheet(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnFirstXclTab, sal_uInt16& rnLastXclTab,
+ SCTAB nFirstScTab, SCTAB nLastScTab, XclExpRefLogEntry* pRefLogEntry )
+{
+ mxImpl->FindExtSheet( rnExtSheet, rnFirstXclTab, rnLastXclTab, nFirstScTab, nLastScTab, pRefLogEntry );
+}
+
+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 ScSingleRefData& rRef )
+{
+ mxImpl->StoreCellRange( rRef, rRef );
+}
+
+void XclExpLinkManager::StoreCellRange( const ScComplexRefData& rRef )
+{
+ mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
+}
+
+void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+{
+ mxImpl->StoreCell( nFileId, rTabName, rRef );
+}
+
+void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+{
+ mxImpl->StoreCellRange( nFileId, rTabName, rRef.Ref1, rRef.Ref2 );
+}
+
+bool XclExpLinkManager::InsertAddIn(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ return mxImpl->InsertAddIn( rnExtSheet, rnExtName, rName );
+}
+
+bool XclExpLinkManager::InsertEuroTool(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+{
+ return mxImpl->InsertEuroTool( rnExtSheet, rnExtName, rName );
+}
+
+bool XclExpLinkManager::InsertDde(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+ const String& rApplic, const String& rTopic, const String& rItem )
+{
+ return mxImpl->InsertDde( rnExtSheet, rnExtName, rApplic, rTopic, rItem );
+}
+
+bool XclExpLinkManager::InsertExtName(
+ sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName, const String& rUrl,
+ const ScExternalRefCache::TokenArrayRef pArray )
+{
+ return mxImpl->InsertExtName( rnExtSheet, rnExtName, rUrl, rName, pArray );
+}
+
+void XclExpLinkManager::Save( XclExpStream& rStrm )
+{
+ mxImpl->Save( rStrm );
+}
+
+// ============================================================================
+