[Libreoffice-commits] .: Branch 'libreoffice-3-4' - 2 commits - sc/inc sc/source

Kohei Yoshida kohei at kemper.freedesktop.org
Wed Apr 13 20:22:54 PDT 2011


 sc/inc/address.hxx                  |    2 
 sc/source/filter/excel/excform8.cxx |   81 ++++++++++++
 sc/source/filter/excel/read.cxx     |    4 
 sc/source/filter/excel/xilink.cxx   |  234 ++++++++++++++++++++++++++++++++----
 sc/source/filter/inc/excform.hxx    |    9 -
 sc/source/filter/inc/xilink.hxx     |   23 +++
 6 files changed, 320 insertions(+), 33 deletions(-)

New commits:
commit 62d20f304c0a5dac17b9bad91a0f110257eaf482
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Wed Apr 13 23:19:36 2011 -0400

    Incorrect index value checking & use operator[] over at().
    
    Take into account that the index value gets subtracted by 1 during
    index value check.  Also, the index access follows after a range
    value check, so there is no need to call at(), operator[] will do.

diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx
index 75b0e1b..492fe5d 100644
--- a/sc/source/filter/excel/xilink.cxx
+++ b/sc/source/filter/excel/xilink.cxx
@@ -700,9 +700,9 @@ void XclImpSupbook::ReadExternname( XclImpStream& rStrm, ExcelToSc* pFormulaConv
 const XclImpExtName* XclImpSupbook::GetExternName( sal_uInt16 nXclIndex ) const
 {
     DBG_ASSERT( nXclIndex > 0, "XclImpSupbook::GetExternName - index must be >0" );
-    if (meType == EXC_SBTYPE_SELF || nXclIndex >= maExtNameList.size())
+    if (meType == EXC_SBTYPE_SELF || nXclIndex > maExtNameList.size())
         return NULL;
-    return &maExtNameList.at( nXclIndex - 1 );
+    return &maExtNameList[nXclIndex-1];
 }
 
 bool XclImpSupbook::GetLinkData( String& rApplic, String& rTopic ) const
commit fd02b1477d07ec14247eedd0546e03790af6a087
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Wed Apr 13 22:35:09 2011 -0400

    Convert OLE links from XLS doc into external ranges on import.
    
    Linked cell ranges that are OLE links to other Excel documents were
    previously ignored on import.  Let's import them but convert them
    into external references which are more robust than OLE links.

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index c39f457..d83caf7 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -487,7 +487,7 @@ public:
                   const ::com::sun::star::uno::Sequence<
                     const ::com::sun::star::sheet::ExternalLinkInfo > * pExternalLinks = NULL );
 
-    sal_uInt16 ParseAny( const String&, ScDocument* = NULL,
+    SC_DLLPUBLIC sal_uInt16 ParseAny( const String&, ScDocument* = NULL,
                      const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 );
     SC_DLLPUBLIC sal_uInt16 ParseCols( const String&, ScDocument* = NULL,
                      const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 );
diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx
index 6dc1834..ab549a4 100644
--- a/sc/source/filter/excel/excform8.cxx
+++ b/sc/source/filter/excel/excform8.cxx
@@ -42,9 +42,51 @@
 #include "externalrefmgr.hxx"
 
 #include <vector>
+#include <cstring>
 
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
 using ::std::vector;
 
+namespace {
+
+/**
+ * Extract a file path from OLE link path.  An OLE link path is expected to
+ * be in the following format:
+ *
+ * Excel.Sheet.8 \3 [file path]
+ */
+bool extractFilePath(const OUString& rUrl, OUString& rPath)
+{
+    const char* prefix = "Excel.Sheet.8\3";
+    size_t nPrefixLen = ::std::strlen(prefix);
+
+    sal_Int32 n = rUrl.getLength();
+    if (n <= static_cast<sal_Int32>(nPrefixLen))
+        // needs to have the specified prefix.
+        return false;
+
+    OUStringBuffer aBuf;
+    const sal_Unicode* p = rUrl.getStr();
+    for (size_t i = 0; i < static_cast<size_t>(n); ++i, ++p)
+    {
+        if (i < nPrefixLen)
+        {
+            sal_Unicode pc = static_cast<sal_Unicode>(*prefix++);
+            if (pc != *p)
+                return false;
+
+            continue;
+        }
+        aBuf.append(*p);
+    }
+
+    rPath = aBuf.makeStringAndClear();
+    return true;
+}
+
+}
+
 ExcelToSc8::ExternalTabInfo::ExternalTabInfo() :
     mnFileId(0), mbExternal(false)
 {
@@ -92,6 +134,20 @@ bool ExcelToSc8::Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB&
     return GetExternalFileIdFromXti(nIxti, rExtInfo.mnFileId);
 }
 
+bool ExcelToSc8::HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo)
+{
+    const String* pUrl = rLinkMan.GetSupbookUrl(nXtiIndex);
+    if (!pUrl)
+        return false;
+
+    OUString aPath;
+    if (!extractFilePath(*pUrl, aPath))
+        // file path extraction failed.
+        return false;
+
+    OUString aFileUrl = ScGlobal::GetAbsDocName(aPath, GetDocShell());
+    return rExtName.CreateOleData(GetDoc(), aFileUrl, rExtInfo.mnFileId, rExtInfo.maTabName, rExtInfo.maRange);
+}
 
 // if bAllowArrays is false stream seeks to first byte after <nFormulaLen>
 // otherwise it will seek to the first byte past additional content after <nFormulaLen>
@@ -682,8 +738,29 @@ ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn,
                                 aStack << aPool.Store( ocEuroConvert, String() );
                             }
                         break;
-
-                        default:    // OLE link
+                        case xlExtOLE:
+                        {
+                            ExternalTabInfo aExtInfo;
+                            if (HandleOleLink(nXtiIndex, *pExtName, aExtInfo))
+                            {
+                                if (aExtInfo.maRange.aStart == aExtInfo.maRange.aEnd)
+                                {
+                                    // single cell
+                                    aSRD.InitAddress(aExtInfo.maRange.aStart);
+                                    aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aSRD);
+                                }
+                                else
+                                {
+                                    // range
+                                    aCRD.InitRange(aExtInfo.maRange);
+                                    aStack << aPool.StoreExtRef(aExtInfo.mnFileId, aExtInfo.maTabName, aCRD);
+                                }
+                            }
+                            else
+                                aStack << aPool.Store(ocNoName, pExtName->GetName());
+                        }
+                        break;
+                        default:
                         {
                             aPool << ocBad;
                             aPool >> aStack;
diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx
index 58aa622..018faaa 100644
--- a/sc/source/filter/excel/read.cxx
+++ b/sc/source/filter/excel/read.cxx
@@ -1125,8 +1125,8 @@ FltError ImportExcel8::Read( void )
                     case 0x9D:  AutoFilterInfo(); break;// AUTOFILTERINFO
                     case 0x9E:  AutoFilter(); break;    // AUTOFILTER
                     case 0x0208: Row34(); break;        // ROW          [  34    ]
-                    case 0x0021:
-                    case 0x0221: Array34(); break;      // ARRAY        [  34    ]
+                    case EXC_ID2_ARRAY:
+                    case EXC_ID3_ARRAY: Array34(); break;      // ARRAY        [  34    ]
                     case 0x0225: Defrowheight345();break;//DEFAULTROWHEI[  345   ]
                     case 0x04BC: Shrfmla(); break;      // SHRFMLA      [    5   ]
                     case 0x0867: SheetProtection(); break; // SHEETPROTECTION
diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx
index 634a723..75b0e1b 100644
--- a/sc/source/filter/excel/xilink.cxx
+++ b/sc/source/filter/excel/xilink.cxx
@@ -44,6 +44,9 @@
 #include <boost/ptr_container/ptr_vector.hpp>
 
 using ::std::vector;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
 
 // ============================================================================
 // *** Helper classes ***
@@ -284,7 +287,61 @@ sal_uInt16 XclImpTabInfo::GetCurrentIndex( sal_uInt16 nCreatedId, sal_uInt16 nMa
 
 // External names =============================================================
 
-XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv )
+XclImpExtName::MOper::MOper(XclImpStream& rStrm) :
+    mxCached(new ScMatrix(0,0))
+{
+    SCSIZE nLastCol = rStrm.ReaduInt8();
+    SCSIZE nLastRow = rStrm.ReaduInt16();
+    mxCached->Resize(nLastCol+1, nLastRow+1);
+    for (SCSIZE nRow = 0; nRow <= nLastRow; ++nRow)
+    {
+        for (SCSIZE nCol = 0; nCol <= nLastCol; ++nCol)
+        {
+            sal_uInt8 nOp;
+            rStrm >> nOp;
+            switch (nOp)
+            {
+                case 0x01:
+                {
+                    double fVal = rStrm.ReadDouble();
+                    mxCached->PutDouble(fVal, nCol, nRow);
+                }
+                break;
+                case 0x02:
+                {
+                    OUString aStr = rStrm.ReadUniString();
+                    mxCached->PutString(aStr, nCol, nRow);
+                }
+                break;
+                case 0x04:
+                {
+                    bool bVal = rStrm.ReaduInt8();
+                    mxCached->PutBoolean(bVal, nCol, nRow);
+                    rStrm.Ignore(7);
+                }
+                break;
+                case 0x10:
+                {
+                    sal_uInt8 nErr = rStrm.ReaduInt8();
+                    // TODO: Map the error code from xls to calc.
+                    mxCached->PutError(nErr, nCol, nRow);
+                    rStrm.Ignore(7);
+                }
+                break;
+                default:
+                    rStrm.Ignore(8);
+            }
+        }
+    }
+}
+
+const ScMatrix& XclImpExtName::MOper::GetCache() const
+{
+    return *mxCached;
+}
+
+XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm, XclSupbookType eSubType, ExcelToSc* pFormulaConv ) :
+    mpMOper(NULL)
 {
     sal_uInt16 nFlags;
     sal_uInt8 nLen;
@@ -312,36 +369,45 @@ XclImpExtName::XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm
         meType = ::get_flagvalue( nFlags, EXC_EXTN_OLE, xlExtOLE, xlExtDDE );
     }
 
-    if( (meType == xlExtDDE) && (rStrm.GetRecLeft() > 1) )
-        mxDdeMatrix.reset( new XclImpCachedMatrix( rStrm ) );
-
-    if (meType == xlExtName)
+    switch (meType)
     {
-        // TODO: For now, only global external names are supported.  In future
-        // we should extend this to supporting per-sheet external names.
-        if (mnStorageId == 0)
-        {
-            if (pFormulaConv)
+        case xlExtDDE:
+            if (rStrm.GetRecLeft() > 1)
+                mxDdeMatrix.reset(new XclImpCachedMatrix(rStrm));
+        break;
+        case xlExtName:
+            // TODO: For now, only global external names are supported.  In future
+            // we should extend this to supporting per-sheet external names.
+            if (mnStorageId == 0)
             {
-                const ScTokenArray* pArray = NULL;
-                sal_uInt16 nFmlaLen;
-                rStrm >> nFmlaLen;
-                vector<String> aTabNames;
-                sal_uInt16 nCount = rSupbook.GetTabCount();
-                aTabNames.reserve(nCount);
-                for (sal_uInt16 i = 0; i < nCount; ++i)
-                    aTabNames.push_back(rSupbook.GetTabName(i));
-
-                pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
-                if (pArray)
-                    mxArray.reset(pArray->Clone());
+                if (pFormulaConv)
+                {
+                    const ScTokenArray* pArray = NULL;
+                    sal_uInt16 nFmlaLen;
+                    rStrm >> nFmlaLen;
+                    vector<String> aTabNames;
+                    sal_uInt16 nCount = rSupbook.GetTabCount();
+                    aTabNames.reserve(nCount);
+                    for (sal_uInt16 i = 0; i < nCount; ++i)
+                        aTabNames.push_back(rSupbook.GetTabName(i));
+
+                    pFormulaConv->ConvertExternName(pArray, rStrm, nFmlaLen, rSupbook.GetXclUrl(), aTabNames);
+                    if (pArray)
+                        mxArray.reset(pArray->Clone());
+                }
             }
-        }
+        break;
+        case xlExtOLE:
+            mpMOper = new MOper(rStrm);
+        break;
+        default:
+            ;
     }
 }
 
 XclImpExtName::~XclImpExtName()
 {
+    delete mpMOper;
 }
 
 void XclImpExtName::CreateDdeData( ScDocument& rDoc, const String& rApplic, const String& rTopic ) const
@@ -361,6 +427,124 @@ void XclImpExtName::CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) co
     pRefMgr->storeRangeNameTokens(nFileId, maName, *mxArray);
 }
 
+namespace {
+
+/**
+ * Decompose the name into sheet name and range name.  An OLE link name is
+ * always formatted like this [ !Sheet1!R1C1:R5C2 ] and it always uses R1C1
+ * notation.
+ */
+bool extractSheetAndRange(const OUString& rName, OUString& rSheet, OUString& rRange)
+{
+    sal_Int32 n = rName.getLength();
+    const sal_Unicode* p = rName.getStr();
+    OUStringBuffer aBuf;
+    bool bInSheet = true;
+    for (sal_Int32 i = 0; i < n; ++i, ++p)
+    {
+        if (i == 0)
+        {
+            // first character must be '!'.
+            if (*p != '!')
+                return false;
+            continue;
+        }
+
+        if (*p == '!')
+        {
+            // sheet name to range separator.
+            if (!bInSheet)
+                return false;
+            rSheet = aBuf.makeStringAndClear();
+            bInSheet = false;
+            continue;
+        }
+
+        aBuf.append(*p);
+    }
+
+    rRange = aBuf.makeStringAndClear();
+    return true;
+}
+
+}
+
+bool XclImpExtName::CreateOleData(ScDocument& rDoc, const OUString& rUrl,
+                                  sal_uInt16& rFileId, OUString& rTabName, ScRange& rRange) const
+{
+    if (!mpMOper)
+        return false;
+
+    OUString aSheet, aRangeStr;
+    if (!extractSheetAndRange(maName, aSheet, aRangeStr))
+        return false;
+
+    ScRange aRange;
+    sal_uInt16 nRes = aRange.ParseAny(aRangeStr, &rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
+    if ((nRes & SCA_VALID) != SCA_VALID)
+        return false;
+
+    if (aRange.aStart.Tab() != aRange.aEnd.Tab())
+        // We don't support multi-sheet range for this.
+        return false;
+
+    const ScMatrix& rCache = mpMOper->GetCache();
+    SCSIZE nC, nR;
+    rCache.GetDimensions(nC, nR);
+    if (!nC || !nR)
+        // cache matrix is empty.
+        return false;
+
+    ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
+    sal_uInt16 nFileId = pRefMgr->getExternalFileId(rUrl);
+    ScExternalRefCache::TableTypeRef xTab = pRefMgr->getCacheTable(nFileId, aSheet, true, NULL);
+    if (!xTab)
+        // cache table creation failed.
+        return false;
+
+    xTab->setWholeTableCached();
+    for (SCSIZE i = 0; i < nR; ++i)
+    {
+        for (SCSIZE j = 0; j < nC; ++j)
+        {
+            SCCOL nCol = aRange.aStart.Col() + j;
+            SCROW nRow = aRange.aStart.Row() + i;
+
+            ScMatrixValue aVal = rCache.Get(j, i);
+            switch (aVal.nType)
+            {
+                case SC_MATVAL_BOOLEAN:
+                {
+                    bool b = aVal.GetBoolean();
+                    ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(b ? 1.0 : 0.0));
+                    xTab->setCell(nCol, nRow, pToken, 0, false);
+                }
+                break;
+                case SC_MATVAL_VALUE:
+                {
+                    ScExternalRefCache::TokenRef pToken(new formula::FormulaDoubleToken(aVal.fVal));
+                    xTab->setCell(nCol, nRow, pToken, 0, false);
+                }
+                break;
+                case SC_MATVAL_STRING:
+                {
+                    const String& rStr = aVal.GetString();
+                    ScExternalRefCache::TokenRef pToken(new formula::FormulaStringToken(rStr));
+                    xTab->setCell(nCol, nRow, pToken, 0, false);
+                }
+                break;
+                default:
+                    ;
+            }
+        }
+    }
+
+    rFileId = nFileId;
+    rTabName = aSheet;
+    rRange = aRange;
+    return true;
+}
+
 bool XclImpExtName::HasFormulaTokens() const
 {
     return (mxArray.get() != NULL);
diff --git a/sc/source/filter/inc/excform.hxx b/sc/source/filter/inc/excform.hxx
index 5dc3c5c..d20ad02 100644
--- a/sc/source/filter/inc/excform.hxx
+++ b/sc/source/filter/inc/excform.hxx
@@ -104,6 +104,7 @@ inline sal_Bool ExcelToSc::IsComplRowRange( const sal_uInt16 nRow1, const sal_uI
 // ============================================================================
 
 class XclImpLinkManager;
+class XclImpExtName;
 
 class ExcelToSc8 : public ExcelToSc
 {
@@ -111,9 +112,10 @@ public:
 
     struct ExternalTabInfo
     {
-        String      maTabName;
-        sal_uInt16  mnFileId;
-        bool        mbExternal;
+        ScRange         maRange;
+        ::rtl::OUString maTabName;
+        sal_uInt16      mnFileId;
+        bool            mbExternal;
 
         ExternalTabInfo();
     };
@@ -128,6 +130,7 @@ private:
 
     virtual bool        Read3DTabReference( sal_uInt16 nIxti, SCTAB& rFirstTab, SCTAB& rLastTab, ExternalTabInfo& rExtInfo );
 
+    bool                HandleOleLink(sal_uInt16 nXtiIndex, const XclImpExtName& rExtName, ExternalTabInfo& rExtInfo);
 public:
                         ExcelToSc8( const XclImpRoot& rRoot );
     virtual				~ExcelToSc8();
diff --git a/sc/source/filter/inc/xilink.hxx b/sc/source/filter/inc/xilink.hxx
index bd2b9c1..ab865d2 100644
--- a/sc/source/filter/inc/xilink.hxx
+++ b/sc/source/filter/inc/xilink.hxx
@@ -32,6 +32,7 @@
 #include <map>
 #include "xllink.hxx"
 #include "xiroot.hxx"
+#include "scmatrix.hxx"
 
 /* ============================================================================
 Classes for import of different kinds of internal/external references.
@@ -113,6 +114,19 @@ class XclImpSupbook;
     @descr Supported: External defined names, AddIn names, DDE links and OLE objects. */
 class XclImpExtName
 {
+    /**
+     * MOper, multiple operands, stores cached values of external range
+     * specified in the record.
+     */
+    class MOper
+    {
+    public:
+        MOper(XclImpStream& rStrm);
+        const ScMatrix& GetCache() const;
+    private:
+        ScMatrixRef mxCached;
+    };
+
 public:
     /** Reads the external name from the stream. */
     explicit            XclImpExtName( const XclImpSupbook& rSupbook, XclImpStream& rStrm,
@@ -125,6 +139,14 @@ public:
 
     void                CreateExtNameData( ScDocument& rDoc, sal_uInt16 nFileId ) const;
 
+    /**
+     * Create OLE link data.  OLE link data is converted to external
+     * reference, since OLE link doesn't work cross-platform, and is not very
+     * reliable even on Windows.
+     */
+    bool CreateOleData(ScDocument& rDoc, const ::rtl::OUString& rUrl,
+                       sal_uInt16& rFileId, ::rtl::OUString& rTabName, ScRange& rRange) const;
+
     bool                HasFormulaTokens() const;
 
     inline XclImpExtNameType GetType() const { return meType; }
@@ -136,6 +158,7 @@ private:
     typedef ::std::auto_ptr< ScTokenArray >       TokenArrayPtr;
 
     XclImpCachedMatrixPtr mxDdeMatrix;      /// Cached results of the DDE link.
+    MOper*              mpMOper;            /// Cached values for OLE link
     TokenArrayPtr       mxArray;            /// Formula tokens for external name.
     String              maName;             /// The name of the external name.
     sal_uInt32          mnStorageId;        /// Storage ID for OLE object storages.


More information about the Libreoffice-commits mailing list