sc/inc/compiler.hxx                          |    7 
 sc/source/core/tool/compiler.cxx             |   90 ++++++-
 sc/source/core/tool/token.cxx                |    7 
 sc/source/filter/excel/excdoc.cxx            |    1 
 sc/source/filter/excel/ooxml-export-TODO.txt |    2 
 sc/source/filter/excel/xecontent.cxx         |    2 
 sc/source/filter/excel/xelink.cxx            |  313 +++++++++++++++++++++++++--
 sc/source/filter/inc/xecontent.hxx           |    7 
 sc/source/filter/inc/xelink.hxx              |    3 
 9 files changed, 387 insertions(+), 45 deletions(-)

New commits:
commit d3483180e684ab8272b30676a395a53c9c7c6ad2
Author: Eike Rathke <er...@redhat.com>
Date:   Tue Aug 5 22:51:01 2014 +0200

    write OOXML externalReferences, externalLinks, fdo#45286
    
    This for the first time writes external references (hopefully) correctly
    and adds the necessary relationship streams and the externalLink streams
    with sheetData. At least Excel 2013 loaded the result without
    complaining, so do we.
    
    (cherry picked from commit 8c23a767d926d8d08213f5e2f8e81775c653cbd7)
    
    Conflicts:
        sc/source/filter/excel/xelink.cxx
    
    do not write empty externalReferences element, fdo#45286 follow-up
    
    OOXML validation spewed
    - (xl/workbook.xml:2 col:700) cvc-complex-type.2.4.b: The content of
      element ´externalReferences´ is not complete. One of
      
´{"http://schemas.openxmlformats.org/spreadsheetml/2006/main":externalReference}´
      is expected.
    
    (cherry picked from commit 8c51532289db36337c4984baec1bf5a7ca9e40af)
    
    really do not write empty externalReferences element, fdo#45286 follow-up
    
    Xti records exist also for internal sheet references in BIFF. It is not
    enough to check for their presence, at least one EXC_SBTYPE_EXTERN must
    be present as SUPBOOK.
    
    (cherry picked from commit e04a4d2d2c18134556bb4e001d497ca7d66c6828)
    
    Change-Id: I3d615490a60c5420ae13c0bfc6297642d86a07b9
    Reviewed-on: https://gerrit.libreoffice.org/10872
    Reviewed-by: Markus Mohrhard <markus.mohrh...@googlemail.com>
    Tested-by: Markus Mohrhard <markus.mohrh...@googlemail.com>

diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 6100835..18d788a 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -256,15 +256,16 @@ public:
                 const ::com::sun::star::uno::Sequence<
                     com::sun::star::sheet::ExternalLinkInfo>* pExternalLinks ) 
const = 0;
 
-        virtual OUString makeExternalNameStr( const OUString& rFile, const 
OUString& rName ) const = 0;
+        virtual OUString makeExternalNameStr( sal_uInt16 nFileId, const 
OUString& rFile,
+                const OUString& rName ) const = 0;
 
         virtual void makeExternalRefStr(
-            OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+            OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
nFileId, const OUString& rFileName,
             const OUString& rTabName, const ScSingleRefData& rRef ) const = 0;
 
         virtual void makeExternalRefStr(
             OUStringBuffer& rBuffer, const ScAddress& rPos,
-            const OUString& rFileName, const std::vector<OUString>& rTabNames,
+            sal_uInt16 nFileId, const OUString& rFileName, const 
std::vector<OUString>& rTabNames,
             const OUString& rTabName, const ScComplexRefData& rRef ) const = 0;
 
         enum SpecialSymbolType
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 8031f8e..bfd8802 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -823,7 +823,8 @@ struct ConventionOOO_A1 : public Convention_A1
         return lcl_parseExternalName(rSymbol, rFile, rName, '#', pDoc, 
pExternalLinks);
     }
 
-    virtual OUString makeExternalNameStr( const OUString& rFile, const 
OUString& rName ) const SAL_OVERRIDE
+    virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const 
OUString& rFile,
+            const OUString& rName ) const SAL_OVERRIDE
     {
         return lcl_makeExternalNameStr( rFile, rName, '#', false);
     }
@@ -874,7 +875,7 @@ struct ConventionOOO_A1 : public Convention_A1
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const OUString& rTabName, const ScSingleRefData& rRef ) const 
SAL_OVERRIDE
     {
         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, 
false);
@@ -921,7 +922,7 @@ struct ConventionOOO_A1 : public Convention_A1
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     {
@@ -966,20 +967,21 @@ struct ConventionOOO_A1_ODF : public ConventionOOO_A1
         rBuffer.append(']');
     }
 
-    virtual OUString makeExternalNameStr( const OUString& rFile, const 
OUString& rName ) const SAL_OVERRIDE
+    virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const 
OUString& rFile,
+            const OUString& rName ) const SAL_OVERRIDE
     {
         return lcl_makeExternalNameStr( rFile, rName, '#', true);
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const OUString& rTabName, const ScSingleRefData& rRef ) const 
SAL_OVERRIDE
     {
         makeExternalRefStrImpl(rBuffer, rPos, rFileName, rTabName, rRef, true);
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames,
         const OUString& rTabName, const ScComplexRefData& rRef ) const 
SAL_OVERRIDE
     {
@@ -1264,13 +1266,14 @@ struct ConventionXL_A1 : public Convention_A1, public 
ConventionXL
         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, 
pExternalLinks);
     }
 
-    virtual OUString makeExternalNameStr( const OUString& rFile, const 
OUString& rName ) const SAL_OVERRIDE
+    virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const 
OUString& rFile,
+            const OUString& rName ) const SAL_OVERRIDE
     {
         return ConventionXL::makeExternalNameStr(rFile, rName);
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const OUString& rTabName, const ScSingleRefData& rRef ) const 
SAL_OVERRIDE
     {
         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
@@ -1287,7 +1290,7 @@ struct ConventionXL_A1 : public Convention_A1, public 
ConventionXL
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     {
@@ -1309,6 +1312,57 @@ struct ConventionXL_A1 : public Convention_A1, public 
ConventionXL
 struct ConventionXL_OOX : public ConventionXL_A1
 {
     ConventionXL_OOX() : ConventionXL_A1( FormulaGrammar::CONV_XL_OOX ) { }
+
+    virtual OUString makeExternalNameStr( sal_uInt16 nFileId, const OUString& 
/*rFile*/,
+            const OUString& rName ) const SAL_OVERRIDE
+    {
+        // [N]!DefinedName is a workbook global name.
+        return OUString( "[" + OUString::number(nFileId+1) + "]!" + rName );
+
+        /* TODO: add support for sheet local names, would be
+         * [N]'Sheet Name'!DefinedName
+         * Similar to makeExternalRefStr() but with DefinedName instead of
+         * CellStr. */
+    }
+
+    virtual void makeExternalRefStr(
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, 
const OUString& /*rFileName*/,
+        const OUString& rTabName, const ScSingleRefData& rRef ) const 
SAL_OVERRIDE
+    {
+        // [N]'Sheet Name'!$A$1
+        // Where N is a 1-based positive integer number of a file name in OOXML
+        // xl/externalLinks/externalLinkN.xml
+
+        ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
+        ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
+        rBuffer.append('!');
+
+        makeSingleCellStr(rBuffer, rRef, rRef.toAbs(rPos));
+    }
+
+    virtual void makeExternalRefStr(
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 nFileId, 
const OUString& /*rFileName*/,
+        const std::vector<OUString>& rTabNames, const OUString& rTabName,
+        const ScComplexRefData& rRef ) const SAL_OVERRIDE
+    {
+        ScRange aAbsRef = rRef.toAbs(rPos);
+
+        ConventionXL_OOX::makeExternalDocStr(rBuffer, nFileId);
+        ConventionXL::makeExternalTabNameRange(rBuffer, rTabName, rTabNames, 
aAbsRef);
+        rBuffer.append('!');
+
+        makeSingleCellStr(rBuffer, rRef.Ref1, aAbsRef.aStart);
+        if (aAbsRef.aStart != aAbsRef.aEnd)
+        {
+            rBuffer.append(':');
+            makeSingleCellStr(rBuffer, rRef.Ref2, aAbsRef.aEnd);
+        }
+    }
+
+    static void makeExternalDocStr( OUStringBuffer& rBuffer, sal_uInt16 
nFileId )
+    {
+        rBuffer.append('[').append( OUString::number( nFileId+1)).append(']');
+    }
 };
 
 static void
@@ -1438,13 +1492,14 @@ struct ConventionXL_R1C1 : public 
ScCompiler::Convention, public ConventionXL
         return ConventionXL::parseExternalName( rSymbol, rFile, rName, pDoc, 
pExternalLinks);
     }
 
-    virtual OUString makeExternalNameStr( const OUString& rFile, const 
OUString& rName ) const SAL_OVERRIDE
+    virtual OUString makeExternalNameStr( sal_uInt16 /*nFileId*/, const 
OUString& rFile,
+            const OUString& rName ) const SAL_OVERRIDE
     {
         return ConventionXL::makeExternalNameStr(rFile, rName);
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const OUString& rTabName, const ScSingleRefData& rRef ) const 
SAL_OVERRIDE
     {
         // ['file:///path/to/file/filename.xls']'Sheet Name'!$A$1
@@ -1463,7 +1518,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, 
public ConventionXL
     }
 
     virtual void makeExternalRefStr(
-        OUStringBuffer& rBuffer, const ScAddress& rPos, const OUString& 
rFileName,
+        OUStringBuffer& rBuffer, const ScAddress& rPos, sal_uInt16 
/*nFileId*/, const OUString& rFileName,
         const std::vector<OUString>& rTabNames, const OUString& rTabName,
         const ScComplexRefData& rRef ) const SAL_OVERRIDE
     {
@@ -4082,30 +4137,31 @@ bool ScCompiler::IsCharFlagAllConventions(
 void ScCompiler::CreateStringFromExternal(OUStringBuffer& rBuffer, 
FormulaToken* pTokenP) const
 {
     FormulaToken* t = pTokenP;
+    sal_uInt16 nFileId = t->GetIndex();
     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
-    const OUString* pFileName = pRefMgr->getExternalFileName(t->GetIndex());
+    const OUString* pFileName = pRefMgr->getExternalFileName(nFileId);
     if (!pFileName)
         return;
 
     switch (t->GetType())
     {
         case svExternalName:
-            rBuffer.append(pConv->makeExternalNameStr(*pFileName, 
t->GetString().getString()));
+            rBuffer.append(pConv->makeExternalNameStr( nFileId, *pFileName, 
t->GetString().getString()));
         break;
         case svExternalSingleRef:
             pConv->makeExternalRefStr(
-                   rBuffer, GetPos(), *pFileName, t->GetString().getString(),
+                   rBuffer, GetPos(), nFileId, *pFileName, 
t->GetString().getString(),
                    static_cast<ScToken*>(t)->GetSingleRef());
         break;
         case svExternalDoubleRef:
         {
             vector<OUString> aTabNames;
-            pRefMgr->getAllCachedTableNames(t->GetIndex(), aTabNames);
+            pRefMgr->getAllCachedTableNames(nFileId, aTabNames);
             if (aTabNames.empty())
                 return;
 
             pConv->makeExternalRefStr(
-                rBuffer, GetPos(), *pFileName, aTabNames, 
t->GetString().getString(),
+                rBuffer, GetPos(), nFileId, *pFileName, aTabNames, 
t->GetString().getString(),
                 static_cast<ScToken*>(t)->GetDoubleRef());
         }
         break;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 4deb0ba..8263380 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -3715,11 +3715,11 @@ void appendTokenByType( sc::TokenStringContext& rCxt, 
OUStringBuffer& rBuf, cons
         switch (rToken.GetType())
         {
             case svExternalName:
-                rBuf.append(rCxt.mpRefConv->makeExternalNameStr(aFileName, 
aTabName));
+                rBuf.append(rCxt.mpRefConv->makeExternalNameStr(nFileId, 
aFileName, aTabName));
             break;
             case svExternalSingleRef:
                 rCxt.mpRefConv->makeExternalRefStr(
-                       rBuf, rPos, aFileName, aTabName, static_cast<const 
ScToken&>(rToken).GetSingleRef());
+                       rBuf, rPos, nFileId, aFileName, aTabName, 
static_cast<const ScToken&>(rToken).GetSingleRef());
             break;
             case svExternalDoubleRef:
             {
@@ -3730,7 +3730,8 @@ void appendTokenByType( sc::TokenStringContext& rCxt, 
OUStringBuffer& rBuf, cons
                     return;
 
                 rCxt.mpRefConv->makeExternalRefStr(
-                    rBuf, rPos, aFileName, it->second, aTabName, 
static_cast<const ScToken&>(rToken).GetDoubleRef());
+                        rBuf, rPos, nFileId, aFileName, it->second, aTabName,
+                        static_cast<const ScToken&>(rToken).GetDoubleRef());
             }
             break;
             default:
diff --git a/sc/source/filter/excel/excdoc.cxx 
b/sc/source/filter/excel/excdoc.cxx
index 40ed956..d5bc941 100644
--- a/sc/source/filter/excel/excdoc.cxx
+++ b/sc/source/filter/excel/excdoc.cxx
@@ -377,6 +377,7 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& 
rBoundsheetList )
 
         // COUNTRY - in BIFF8 in workbook globals
         Add( new XclExpCountry( GetRoot() ) );
+
         // link table: SUPBOOK, XCT, CRN, EXTERNNAME, EXTERNSHEET, NAME
         aRecList.AppendRecord( CreateRecord( EXC_ID_EXTERNSHEET ) );
         aRecList.AppendRecord( CreateRecord( EXC_ID_NAME ) );
diff --git a/sc/source/filter/excel/ooxml-export-TODO.txt 
b/sc/source/filter/excel/ooxml-export-TODO.txt
index 9926cfd..c72b956 100644
--- a/sc/source/filter/excel/ooxml-export-TODO.txt
+++ b/sc/source/filter/excel/ooxml-export-TODO.txt
@@ -30,8 +30,6 @@ Elements:
     - Workbook (§3.2):
         - customWorkbookViews (§3.2.3)
         - ext (§3.2.7)
-        - externalReference (§3.2.8)
-        - externalReferences (§3.2.9)
         - extLst (§3.2.10)
         - fileRecoveryPr (§3.2.11)      [ CRASHRECERR? 865h ]
         - fileSharing (§3.2.12)         [ FILESHARING 5Bh ]
diff --git a/sc/source/filter/excel/xecontent.cxx 
b/sc/source/filter/excel/xecontent.cxx
index ab47be4d..f0e8a07 100644
--- a/sc/source/filter/excel/xecontent.cxx
+++ b/sc/source/filter/excel/xecontent.cxx
@@ -444,7 +444,7 @@ XclExpHyperlink::~XclExpHyperlink()
 }
 
 OUString XclExpHyperlink::BuildFileName(
-        sal_uInt16& rnLevel, bool& rbRel, const OUString& rUrl, const 
XclExpRoot& rRoot ) const
+        sal_uInt16& rnLevel, bool& rbRel, const OUString& rUrl, const 
XclExpRoot& rRoot )
 {
     OUString aDosName( INetURLObject( rUrl ).getFSysPath( 
INetURLObject::FSYS_DOS ) );
     rnLevel = 0;
diff --git a/sc/source/filter/excel/xelink.cxx 
b/sc/source/filter/excel/xelink.cxx
index 944a072..234e65b 100644
--- a/sc/source/filter/excel/xelink.cxx
+++ b/sc/source/filter/excel/xelink.cxx
@@ -27,6 +27,7 @@
 #include "scextopt.hxx"
 #include "externalrefmgr.hxx"
 #include "tokenarray.hxx"
+#include "xecontent.hxx"
 
 #include <vector>
 #include <memory>
@@ -36,6 +37,7 @@ using ::std::find_if;
 using ::std::vector;
 using ::com::sun::star::uno::Any;
 
+using namespace oox;
 
 // *** Helper classes ***
 
@@ -160,6 +162,9 @@ public:
     /** Returns true, if the passed value could be appended to this record. */
     bool                InsertValue( SCCOL nScCol, SCROW nScRow, const Any& 
rValue );
 
+    /** Writes the row and child elements. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 private:
     virtual void        WriteBody( XclExpStream& rStrm ) SAL_OVERRIDE;
 
@@ -177,6 +182,8 @@ private:
     SCROW               mnScRow;    /// Row index of the external cells.
 };
 
+namespace { class XclExpCrnList; }
+
 /** Represents the record XCT which is the header record of a CRN record list.
  */
 class XclExpXct : public XclExpRecordBase, protected XclExpRoot
@@ -198,12 +205,18 @@ public:
     /** Writes the XCT and all CRN records. */
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    /** Writes the sheetDataSet and child elements. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 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.
+
+    /** Build the internal representation of records to be saved as BIFF or 
OOXML. */
+    bool                BuildCrnList( XclExpCrnList& rCrnRecs );
 };
 
 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
@@ -224,8 +237,10 @@ public:
 protected:
     /** Creates and returns the list of EXTERNNAME records. */
     XclExpExtNameBuffer& GetExtNameBuffer();
-    /** Creates and returns the list of EXTERNNAME records. */
+    /** Writes the list of EXTERNNAME records. */
     void                WriteExtNameBuffer( XclExpStream& rStrm );
+    /** Writes the list of externalName elements. */
+    void                WriteExtNameBufferXml( XclExpXmlStream& rStrm );
 
 private:
     typedef boost::shared_ptr< XclExpExtNameBuffer >   XclExpExtNameBfrRef;
@@ -309,9 +324,21 @@ public:
 
     sal_uInt16          InsertExtName( const OUString& rName, const 
ScExternalRefCache::TokenArrayRef pArray );
 
+    /** Get the type of record. */
+    XclSupbookType      GetType() const;
+
+    /** For references to an external document, 1-based OOXML file ID. */
+    sal_uInt16          GetFileId() const;
+
+    /** For references to an external document. */
+    const OUString&     GetUrl() const;
+
     /** Writes the SUPBOOK and all EXTERNNAME, XCT and CRN records. */
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    /** Writes the externalBook and all child elements. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 private:
     /** Returns the sheet name inside of this SUPBOOK. */
     const XclExpString* GetTabName( sal_uInt16 nSBTab ) const;
@@ -329,6 +356,7 @@ private:
     XclExpString        maUrlEncoded;   /// Document name encoded for Excel.
     XclSupbookType      meType;         /// Type of this SUPBOOK record.
     sal_uInt16          mnXclTabCount;  /// Number of internal sheets.
+    sal_uInt16          mnFileId;       /// 1-based external reference file ID 
for OOXML
 };
 
 // All SUPBOOKS in a document =================================================
@@ -403,6 +431,12 @@ public:
     /** Writes all SUPBOOK records with their sub records. */
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    /** Writes all externalBook elements with their child elements to OOXML. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
+    /** Whether we need to write externalReferences or not. */
+    bool                HasExternalReferences() const;
+
     struct XclExpSBIndex
     {
         sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel 
sheet.
@@ -486,6 +520,9 @@ public:
     /** Derived classes write the entire link table to the passed stream. */
     virtual void        Save( XclExpStream& rStrm ) = 0;
 
+    /** Derived classes write the entire link table to the passed OOXML 
stream. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) = 0;
+
 protected:
     explicit            XclExpLinkManagerImpl( const XclExpRoot& rRoot );
 };
@@ -530,6 +567,8 @@ public:
 
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 private:
     typedef XclExpRecordList< XclExpExternSheet >   XclExpExtSheetList;
     typedef XclExpExtSheetList::RecordRefType       XclExpExtSheetRef;
@@ -558,7 +597,7 @@ private:
     XclExpCodeMap       maCodeMap;          /// Maps special external codes to 
EXTERNSHEET records.
 };
 
-/** Implementation of the link manager for BIFF8. */
+/** Implementation of the link manager for BIFF8 and OOXML. */
 class XclExpLinkManagerImpl8 : public XclExpLinkManagerImpl
 {
 public:
@@ -597,6 +636,8 @@ public:
 
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 private:
     /** Searches for or inserts a new XTI structure.
         @return  The 0-based list index of the XTI structure. */
@@ -1152,6 +1193,69 @@ void XclExpCrn::WriteEmpty( XclExpStream& rStrm )
     rStrm.WriteZeroBytes( 8 );
 }
 
+void XclExpCrn::SaveXml( XclExpXmlStream& rStrm )
+{
+    sax_fastparser::FSHelperPtr pFS = rStrm.GetCurrentStream();
+
+    pFS->startElement( XML_row,
+            XML_r,  OString::number( mnScRow + 1 ).getStr(),
+            FSEND);
+
+    ScAddress aAdr( mnScCol, mnScRow, 0);   // Tab number doesn't matter
+    for( CachedValues::iterator aIt = maValues.begin(), aEnd = maValues.end(); 
aIt != aEnd; ++aIt, aAdr.IncCol() )
+    {
+        if( aIt->has< double >() )
+        {
+            double fVal = aIt->get< double >();
+            if (rtl::math::isFinite( fVal))
+            {
+                // t='n' is omitted
+                pFS->startElement( XML_cell,
+                        XML_r,      XclXmlUtils::ToOString( aAdr),
+                        FSEND);
+                pFS->startElement( XML_v, FSEND );
+                pFS->write( fVal );
+            }
+            else
+            {
+                pFS->startElement( XML_cell,
+                        XML_r,      XclXmlUtils::ToOString( aAdr),
+                        XML_t,      "e",
+                        FSEND);
+                pFS->startElement( XML_v, FSEND );
+                pFS->write( "#VALUE!" );    // OOXTODO: support other error 
values
+            }
+        }
+        else if( aIt->has< OUString >() )
+        {
+            pFS->startElement( XML_cell,
+                    XML_r,      XclXmlUtils::ToOString( aAdr),
+                    XML_t,      "str",
+                    FSEND);
+            pFS->startElement( XML_v, FSEND );
+            pFS->write( aIt->get< OUString >() );
+        }
+        else if( aIt->has< bool >() )
+        {
+            pFS->startElement( XML_cell,
+                    XML_r,      XclXmlUtils::ToOString( aAdr),
+                    XML_t,      "b",
+                    FSEND);
+            pFS->startElement( XML_v, FSEND );
+            pFS->write( aIt->get< bool >() ? "1" : "0" );
+        }
+        // OOXTODO: error type cell t='e'
+        else
+        {
+            // Empty/blank cell not stored, only aAdr is incremented.
+        }
+        pFS->endElement( XML_v );
+        pFS->endElement( XML_cell);
+    }
+
+    pFS->endElement( XML_row);
+}
+
 // Cached cells of a sheet ====================================================
 
 XclExpXct::XclExpXct( const XclExpRoot& rRoot, const OUString& rTabName,
@@ -1211,10 +1315,10 @@ bool XclExpCrnList::InsertValue( SCCOL nScCol, SCROW 
nScRow, const Any& rValue )
 
 } // namespace
 
-void XclExpXct::Save( XclExpStream& rStrm )
+bool XclExpXct::BuildCrnList( XclExpCrnList& rCrnRecs )
 {
     if( !mxCacheTable )
-        return;
+        return false;
 
     /*  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
@@ -1222,24 +1326,23 @@ void XclExpXct::Save( XclExpStream& rStrm )
         formulas. */
     ::std::pair< SCROW, SCROW > aRowRange = mxCacheTable->getRowRange();
     if( aRowRange.first >= aRowRange.second )
-        return;
+        return false;
 
     /*  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;
+        return false;
 
     /*  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;
+        return false;
 
     /*  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 )
@@ -1256,13 +1359,13 @@ void XclExpXct::Save( XclExpStream& rStrm )
                 {
                     case svDouble:
                         bValid = (rFormatter.GetType( nScNumFmt ) == 
NUMBERFORMAT_LOGICAL) ?
-                            aCrnRecs.InsertValue( nScCol, nScRow, Any( 
xToken->GetDouble() != 0 ) ) :
-                            aCrnRecs.InsertValue( nScCol, nScRow, Any( 
xToken->GetDouble() ) );
+                            rCrnRecs.InsertValue( nScCol, nScRow, Any( 
xToken->GetDouble() != 0 ) ) :
+                            rCrnRecs.InsertValue( nScCol, nScRow, Any( 
xToken->GetDouble() ) );
                     break;
                     case svString:
                         // do not save empty strings (empty cells) to cache
                         if( !xToken->GetString().isEmpty() )
-                            bValid = aCrnRecs.InsertValue( nScCol, nScRow, 
Any( xToken->GetString().getString() ) );
+                            bValid = rCrnRecs.InsertValue( nScCol, nScRow, 
Any( xToken->GetString().getString() ) );
                     break;
                     default:
                     break;
@@ -1270,6 +1373,14 @@ void XclExpXct::Save( XclExpStream& rStrm )
             }
         }
     }
+    return true;
+}
+
+void XclExpXct::Save( XclExpStream& rStrm )
+{
+    XclExpCrnList aCrnRecs;
+    if (!BuildCrnList( aCrnRecs))
+        return;
 
     // write the XCT record and the list of CRN records
     rStrm.StartRecord( EXC_ID_XCT, 4 );
@@ -1278,6 +1389,22 @@ void XclExpXct::Save( XclExpStream& rStrm )
     aCrnRecs.Save( rStrm );
 }
 
+void XclExpXct::SaveXml( XclExpXmlStream& rStrm )
+{
+    XclExpCrnList aCrnRecs;
+    if (!BuildCrnList( aCrnRecs))
+        return;
+
+    sax_fastparser::FSHelperPtr pFS = rStrm.GetCurrentStream();
+
+    pFS->startElement( XML_sheetData,
+            XML_sheetId,    OString::number( mnSBTab).getStr(),
+            FSEND);
+    // row elements
+    aCrnRecs.SaveXml( rStrm );
+    pFS->endElement( XML_sheetData);
+}
+
 // External documents (EXTERNSHEET/SUPBOOK), base class =======================
 
 XclExpExternSheetBase::XclExpExternSheetBase( const XclExpRoot& rRoot, 
sal_uInt16 nRecId, sal_uInt32 nRecSize ) :
@@ -1299,6 +1426,12 @@ void XclExpExternSheetBase::WriteExtNameBuffer( 
XclExpStream& rStrm )
         mxExtNameBfr->Save( rStrm );
 }
 
+void XclExpExternSheetBase::WriteExtNameBufferXml( XclExpXmlStream& rStrm )
+{
+    if( mxExtNameBfr )
+        mxExtNameBfr->SaveXml( rStrm );
+}
+
 // External documents (EXTERNSHEET, BIFF5/BIFF7) ==============================
 
 XclExpExternSheet::XclExpExternSheet( const XclExpRoot& rRoot, sal_Unicode 
cCode ) :
@@ -1349,14 +1482,16 @@ void XclExpExternSheet::WriteBody( XclExpStream& rStrm )
 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, sal_uInt16 nXclTabCount 
) :
     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
     meType( EXC_SBTYPE_SELF ),
-    mnXclTabCount( nXclTabCount )
+    mnXclTabCount( nXclTabCount ),
+    mnFileId( 0 )
 {
 }
 
 XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot ) :
     XclExpExternSheetBase( rRoot, EXC_ID_SUPBOOK, 4 ),
     meType( EXC_SBTYPE_ADDIN ),
-    mnXclTabCount( 1 )
+    mnXclTabCount( 1 ),
+    mnFileId( 0 )
 {
 }
 
@@ -1365,7 +1500,8 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, 
const OUString& rUrl, Xcl
     maUrl( rUrl ),
     maUrlEncoded( rUrl ),
     meType( EXC_SBTYPE_EUROTOOL ),
-    mnXclTabCount( 0 )
+    mnXclTabCount( 0 ),
+    mnFileId( 0 )
 {
     SetRecSize( 2 + maUrlEncoded.GetSize() );
 }
@@ -1376,13 +1512,15 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, 
const OUString& rUrl ) :
     maUrl( rUrl ),
     maUrlEncoded( XclExpUrlHelper::EncodeUrl( rRoot, rUrl ) ),
     meType( EXC_SBTYPE_EXTERN ),
-    mnXclTabCount( 0 )
+    mnXclTabCount( 0 ),
+    mnFileId( 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 );
+    mnFileId = nFileId + 1;
     ScfStringVec aTabNames;
     pRefMgr->getAllCachedTableNames( nFileId, aTabNames );
     for( ScfStringVec::const_iterator aBeg = aTabNames.begin(), aIt = aBeg, 
aEnd = aTabNames.end(); aIt != aEnd; ++aIt )
@@ -1395,7 +1533,8 @@ XclExpSupbook::XclExpSupbook( const XclExpRoot& rRoot, 
const OUString& rApplic,
     maDdeTopic( rTopic ),
     maUrlEncoded( XclExpUrlHelper::EncodeDde( rApplic, rTopic ) ),
     meType( EXC_SBTYPE_SPECIAL ),
-    mnXclTabCount( 0 )
+    mnXclTabCount( 0 ),
+    mnFileId( 0 )
 {
     SetRecSize( 2 + maUrlEncoded.GetSize() );
 }
@@ -1486,6 +1625,21 @@ sal_uInt16 XclExpSupbook::InsertExtName( const OUString& 
rName, const ScExternal
     return GetExtNameBuffer().InsertExtName(*this, rName, pArray);
 }
 
+XclSupbookType XclExpSupbook::GetType() const
+{
+    return meType;
+}
+
+sal_uInt16 XclExpSupbook::GetFileId() const
+{
+    return mnFileId;
+}
+
+const OUString& XclExpSupbook::GetUrl() const
+{
+    return maUrl;
+}
+
 void XclExpSupbook::Save( XclExpStream& rStrm )
 {
     // SUPBOOK record
@@ -1496,6 +1650,48 @@ void XclExpSupbook::Save( XclExpStream& rStrm )
     WriteExtNameBuffer( rStrm );
 }
 
+void XclExpSupbook::SaveXml( XclExpXmlStream& rStrm )
+{
+    sax_fastparser::FSHelperPtr pExternalLink = rStrm.GetCurrentStream();
+
+    // Add relation for this stream, e.g. 
xl/externalLinks/_rels/externalLink1.xml.rels
+    sal_uInt16 nLevel = 0;
+    bool bRel = true;
+    OUString sId = rStrm.addRelation( pExternalLink->getOutputStream(),
+            
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath";,
+            XclExpHyperlink::BuildFileName( nLevel, bRel, maUrl, GetRoot()),
+            true );
+
+    pExternalLink->startElement( XML_externalLink,
+            XML_xmlns,              
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";,
+            FSEND);
+
+    pExternalLink->startElement( XML_externalBook,
+            FSNS(XML_xmlns, XML_r), 
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";,
+            FSNS(XML_r, XML_id),    XclXmlUtils::ToOString( sId ).getStr(),
+            FSEND);
+
+    pExternalLink->startElement( XML_sheetNames, FSEND);
+    for (size_t nPos = 0, nSize = maXctList.GetSize(); nPos < nSize; ++nPos)
+    {
+        pExternalLink->singleElement( XML_sheetName,
+                XML_val,    XclXmlUtils::ToOString( maXctList.GetRecord( nPos 
)->GetTabName()).getStr(),
+                FSEND);
+    }
+    pExternalLink->endElement( XML_sheetNames);
+
+    pExternalLink->startElement( XML_sheetDataSet, FSEND);
+
+    // sheetData elements
+    maXctList.SaveXml( rStrm );
+    // externalName elements
+    WriteExtNameBufferXml( rStrm );
+
+    pExternalLink->endElement( XML_sheetDataSet);
+    pExternalLink->endElement( XML_externalBook);
+    pExternalLink->endElement( XML_externalLink);
+}
+
 const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
 {
     XclExpXctRef xXct = maXctList.GetRecord( nSBTab );
@@ -1855,6 +2051,58 @@ void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
     maSupbookList.Save( rStrm );
 }
 
+void XclExpSupbookBuffer::SaveXml( XclExpXmlStream& rStrm )
+{
+    ::std::map< sal_uInt16, OUString > aMap;
+    for (size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; 
++nPos)
+    {
+        XclExpSupbookRef xRef( maSupbookList.GetRecord( nPos));
+        if (xRef->GetType() != EXC_SBTYPE_EXTERN)
+            continue;   // handle only external reference (for now?)
+
+        sal_uInt16 nId = xRef->GetFileId();
+        const OUString& rUrl = xRef->GetUrl();
+        ::std::pair< ::std::map< sal_uInt16, OUString >::iterator, bool > 
xInsert(
+                aMap.insert( ::std::make_pair( nId, rUrl)));
+        if (!xInsert.second)
+        {
+            SAL_WARN( "sc.filter", "XclExpSupbookBuffer::SaveXml: file ID 
already used: " << nId <<
+                    " wanted for " << rUrl << " and is " << 
(*xInsert.first).second <<
+                    (rUrl == (*xInsert.first).second ? " multiple Supbook not 
supported" : ""));
+            continue;
+        }
+
+        OUString sId;
+        sax_fastparser::FSHelperPtr pExternalLink = rStrm.CreateOutputStream(
+                XclXmlUtils::GetStreamName( "xl/", 
"externalLinks/externalLink", nId),
+                XclXmlUtils::GetStreamName( NULL, 
"externalLinks/externalLink", nId),
+                rStrm.GetCurrentStream()->getOutputStream(),
+                
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
+                CREATE_OFFICEDOC_RELATION_TYPE("externalLink"),
+                &sId );
+
+        // externalReference entry in workbook externalReferences
+        rStrm.GetCurrentStream()->singleElement( XML_externalReference,
+                FSNS( XML_r, XML_id ),  XclXmlUtils::ToOString( sId ).getStr(),
+                FSEND );
+
+        // Each externalBook in a separate stream.
+        rStrm.PushStream( pExternalLink );
+        xRef->SaveXml( rStrm );
+        rStrm.PopStream();
+    }
+}
+
+bool XclExpSupbookBuffer::HasExternalReferences() const
+{
+    for (size_t nPos = 0, nSize = maSupbookList.GetSize(); nPos < nSize; 
++nPos)
+    {
+        if (maSupbookList.GetRecord( nPos)->GetType() == EXC_SBTYPE_EXTERN)
+            return true;
+    }
+    return false;
+}
+
 bool XclExpSupbookBuffer::GetSupbookUrl(
         XclExpSupbookRef& rxSupbook, sal_uInt16& rnIndex, const OUString& rUrl 
) const
 {
@@ -1998,6 +2246,11 @@ void XclExpLinkManagerImpl5::Save( XclExpStream& rStrm )
     }
 }
 
+void XclExpLinkManagerImpl5::SaveXml( XclExpXmlStream& /*rStrm*/ )
+{
+    // not applicable
+}
+
 sal_uInt16 XclExpLinkManagerImpl5::GetExtSheetCount() const
 {
     return static_cast< sal_uInt16 >( maExtSheetList.GetSize() );
@@ -2216,6 +2469,29 @@ void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
     }
 }
 
+void XclExpLinkManagerImpl8::SaveXml( XclExpXmlStream& rStrm )
+{
+    if (maSBBuffer.HasExternalReferences())
+    {
+        sax_fastparser::FSHelperPtr pWorkbook = rStrm.GetCurrentStream();
+        pWorkbook->startElement( XML_externalReferences, FSEND);
+
+        // externalLink, externalBook, sheetNames, sheetDataSet, externalName
+        maSBBuffer.SaveXml( rStrm );
+
+        pWorkbook->endElement( XML_externalReferences);
+    }
+
+    // TODO: equivalent for EXTERNSHEET in OOXML?
+#if 0
+    if( !maXtiVec.empty() )
+    {
+        for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = 
maXtiVec.end(); aIt != aEnd; ++aIt )
+            aIt->SaveXml( rStrm );
+    }
+#endif
+}
+
 sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
 {
     for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = 
maXtiVec.end(); aIt != aEnd; ++aIt )
@@ -2322,4 +2598,9 @@ void XclExpLinkManager::Save( XclExpStream& rStrm )
     mxImpl->Save( rStrm );
 }
 
+void XclExpLinkManager::SaveXml( XclExpXmlStream& rStrm )
+{
+    mxImpl->SaveXml( rStrm );
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/filter/inc/xecontent.hxx 
b/sc/source/filter/inc/xecontent.hxx
index 0a6705c..2142293 100644
--- a/sc/source/filter/inc/xecontent.hxx
+++ b/sc/source/filter/inc/xecontent.hxx
@@ -110,13 +110,14 @@ public:
 
     virtual void        WriteEmbeddedData( XclExpStream& rStrm );
     void                SetDisplay( bool bDisplay ) { mbSetDisplay = bDisplay; 
}
-private:
+
     /** Builds file name from the passed file URL. Tries to convert to 
relative file name.
         @param rnLevel  (out-param) The parent directory level.
         @param rbRel  (out-param) true = path is relative. */
-    OUString            BuildFileName(
+    static OUString     BuildFileName(
                             sal_uInt16& rnLevel, bool& rbRel,
-                            const OUString& rUrl, const XclExpRoot& rRoot ) 
const;
+                            const OUString& rUrl, const XclExpRoot& rRoot );
+private:
 
     /** Writes the body of the HLINK record. */
     virtual void        WriteBody( XclExpStream& rStrm ) SAL_OVERRIDE;
diff --git a/sc/source/filter/inc/xelink.hxx b/sc/source/filter/inc/xelink.hxx
index 444192e..89d8b2f 100644
--- a/sc/source/filter/inc/xelink.hxx
+++ b/sc/source/filter/inc/xelink.hxx
@@ -200,6 +200,9 @@ public:
     /** Writes the entire Link table. */
     virtual void        Save( XclExpStream& rStrm ) SAL_OVERRIDE;
 
+    /** Writes the entire Link table to OOXML. */
+    virtual void        SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
+
 private:
     typedef boost::shared_ptr< XclExpLinkManagerImpl > XclExpLinkMgrImplPtr;
     XclExpLinkMgrImplPtr mxImpl;
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to