[ooo-build-commit] Branch 'ooo/master' - oox/inc oox/source

Jan Holesovsky kendy at kemper.freedesktop.org
Wed Jul 29 10:39:57 PDT 2009


 oox/inc/oox/xls/formulabase.hxx       |   94 +---
 oox/inc/oox/xls/formulaparser.hxx     |   65 ++
 oox/inc/oox/xls/ooxformulaparser.hxx  |  115 +++++
 oox/inc/oox/xls/workbookhelper.hxx    |    2 
 oox/source/core/facreg.cxx            |    6 
 oox/source/token/properties.txt       |    1 
 oox/source/xls/externallinkbuffer.cxx |    5 
 oox/source/xls/formulabase.cxx        |  367 ++++++++++------
 oox/source/xls/formulaparser.cxx      |  778 ++++++++++++++++------------------
 oox/source/xls/makefile.mk            |    1 
 oox/source/xls/ooxformulaparser.cxx   |  228 +++++++++
 11 files changed, 1085 insertions(+), 577 deletions(-)

New commits:
commit 0ef2bcfac1e81c01ac38645108e75f750397bfbb
Author: Jens-Heiner Rechtien <hr at openoffice.org>
Date:   Wed Jul 29 14:46:52 2009 +0000

    CWS-TOOLING: integrate CWS dr71
    2009-07-07 16:26:00 +0200 dr  r273805 : #i10000# unused variables
    2009-07-07 10:27:14 +0200 dr  r273780 : CWS-TOOLING: rebase CWS dr71 to trunk at 273468 (milestone: DEV300:m51)
    2009-07-01 11:28:24 +0200 dr  r273559 : #101471# special handling for XL library functions in ODF formulas (EUROCONVERT)
    2009-06-29 17:48:46 +0200 dr  r273478 : #i101471# typo
    2009-06-29 17:35:16 +0200 dr  r273477 : #i101471# import msoxl: formulas from conditional formatting and data validation
    2009-06-18 13:45:17 +0200 dr  r273115 : #101471# changed interface css.sheet.XFormulaParser
    2009-06-18 13:44:43 +0200 dr  r273114 : #101471# changed interface css.sheet.XFormulaParser
    2009-06-17 17:29:23 +0200 dr  r273089 : #i101471# extend the XFormulaParser interface with a ReferencePosition parameter, make rel-refs from msoxl: namespace working
    2009-06-17 17:28:39 +0200 dr  r273088 : #i101471# extend the XFormulaParser interface with a ReferencePosition parameter
    2009-06-17 17:28:19 +0200 dr  r273087 : #i101471# extend the XFormulaParser interface with a ReferencePosition parameter
    2009-06-17 17:27:19 +0200 dr  r273086 : #i101471# extend the XFormulaParser interface with a ReferencePosition parameter, remove that property from FormulaParser service
    2009-06-17 12:52:20 +0200 dr  r273059 : #i101471# import cell formulas from msoxl: namespace
    2009-06-16 11:40:50 +0200 dr  r273013 : #i101471# import formula namespace from xml elements
    2009-06-12 18:34:13 +0200 dr  r272935 : #i101471# external formula parser for oox in odf
    2009-06-12 18:33:13 +0200 dr  r272934 : #i101471# external formula parsers
    2009-06-12 18:29:46 +0200 dr  r272933 : #i101471# external formula parsers
    2009-06-05 15:53:47 +0200 dr  r272705 : #i101471# provide OOX formula parser as UNO service

diff --git a/oox/inc/oox/xls/formulabase.hxx b/oox/inc/oox/xls/formulabase.hxx
index 157b905..b2e576d 100644
--- a/oox/inc/oox/xls/formulabase.hxx
+++ b/oox/inc/oox/xls/formulabase.hxx
@@ -37,9 +37,11 @@
 #include <com/sun/star/sheet/FormulaToken.hpp>
 #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp>
 #include "oox/helper/containerhelper.hxx"
+#include "oox/helper/propertyset.hxx"
 #include "oox/xls/addressconverter.hxx"
 
 namespace com { namespace sun { namespace star {
+    namespace sheet { class XFormulaParser; }
     namespace sheet { class XFormulaTokens; }
     namespace sheet { class XFormulaOpCodeMapper; }
 } } }
@@ -409,6 +411,8 @@ struct FunctionInfo
     bool                mbVarParam;         /// True = use a tFuncVar token, also if min/max are equal.
 };
 
+typedef RefVector< FunctionInfo > FunctionInfoVector;
+
 // function info parameter class iterator =====================================
 
 /** Iterator working on the mpnParamClass member of the FunctionInfo struct.
@@ -437,8 +441,7 @@ private:
 
 // base function provider =====================================================
 
-class FunctionProviderImpl;
-namespace { struct FunctionData; }
+struct FunctionProviderImpl;
 
 /** Provides access to function info structs for all available sheet functions.
  */
@@ -464,47 +467,38 @@ public:
         EXTERN.CALL function, or 0 on error. */
     const FunctionInfo* getFuncInfoFromMacroName( const ::rtl::OUString& rFuncName ) const;
 
-protected:
-    typedef RefVector< FunctionInfo >               FuncVector;
-    typedef RefMap< ::rtl::OUString, FunctionInfo > FuncNameMap;
-    typedef RefMap< sal_uInt16, FunctionInfo >      FuncIdMap;
-
-    typedef ::boost::shared_ptr< FuncVector >       FuncVectorRef;
-    typedef ::boost::shared_ptr< FuncNameMap >      FuncNameMapRef;
-    typedef ::boost::shared_ptr< FuncIdMap >        FuncIdMapRef;
+    /** Returns the library type associated with the passed URL of a function
+        library (function add-in). */
+    FunctionLibraryType getFuncLibTypeFromLibraryName( const ::rtl::OUString& rLibraryName ) const;
 
+protected:
     /** Returns the list of all function infos. */
-    inline const FuncVector& getFuncs() const { return *mxFuncs; }
-
-private:
-    /** Creates and inserts a function info struct from the passed function data. */
-    void                initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam );
-
-    /** Initializes the members from the passed function data list. */
-    void                initFuncs(
-                            const FunctionData* pBeg, const FunctionData* pEnd,
-                            sal_uInt8 nMaxParam, bool bImportFilter );
+    const FunctionInfoVector& getFuncs() const;
 
 private:
-    FuncVectorRef       mxFuncs;            /// All function infos in one list.
-    FuncNameMapRef      mxOdfFuncs;         /// Maps ODF function names to function data.
-    FuncNameMapRef      mxOoxFuncs;         /// Maps OOXML function names to function data.
-    FuncIdMapRef        mxOobFuncs;         /// Maps OOBIN function indexes to function data.
-    FuncIdMapRef        mxBiffFuncs;        /// Maps BIFF function indexes to function data.
-    FuncNameMapRef      mxMacroFuncs;       /// Maps macro function names to function data.
+    typedef ::boost::shared_ptr< FunctionProviderImpl > FunctionProviderImplRef;
+    FunctionProviderImplRef mxFuncImpl;     /// Shared implementation between all copies of the provider.
 };
 
 // op-code and function provider ==============================================
 
+struct OpCodeProviderImpl;
+
 /** Provides access to API op-codes for all available formula tokens and to
     function info structs for all available sheet functions.
  */
-class OpCodeProvider : public ApiOpCodes, public FunctionProvider, public WorkbookHelper
+class OpCodeProvider : public FunctionProvider // not derived from WorkbookHelper to make it usable as UNO service
 {
 public:
-    explicit            OpCodeProvider( const WorkbookHelper& rHelper );
+    explicit            OpCodeProvider(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxFactory,
+                            FilterType eFilter, BiffType eBiff, bool bImportFilter );
     virtual             ~OpCodeProvider();
 
+    /** Returns the structure containing all token op-codes for operators and
+        special tokens used by the Calc document and its formula parser. */
+    const ApiOpCodes&   getOpCodes() const;
+
     /** Returns the function info for an API token, or 0 on error. */
     const FunctionInfo* getFuncInfoFromApiToken( const ApiToken& rToken ) const;
 
@@ -513,30 +507,32 @@ public:
                         getOoxParserMap() const;
 
 private:
-    typedef ::std::map< ::rtl::OUString, ApiToken >                                             ApiTokenMap;
-    typedef ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaOpCodeMapEntry >   OpCodeEntrySequence;
-    typedef ::std::vector< ::com::sun::star::sheet::FormulaOpCodeMapEntry >                     OpCodeEntryVector;
+    typedef ::boost::shared_ptr< OpCodeProviderImpl > OpCodeProviderImplRef;
+    OpCodeProviderImplRef mxOpCodeImpl;     /// Shared implementation between all copies of the provider.
+};
 
-    static bool         fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
-    static bool         fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
-    bool                fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaOpCodeMapper >& rxMapper ) const;
+// API formula parser wrapper =================================================
 
-    static bool         initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
-    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const ::rtl::OUString& rOdfName, const ::rtl::OUString& rOoxName );
-    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName );
-    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
+/** A wrapper around the FormulaParser service provided by the Calc document. */
+class ApiParserWrapper : public OpCodeProvider
+{
+public:
+    explicit            ApiParserWrapper(
+                            const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxFactory,
+                            const OpCodeProvider& rOpCodeProv );
 
-    bool                initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
-    bool                initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap );
+    /** Returns read/write access to the formula parser property set. */
+    inline PropertySet& getParserProperties() { return maParserProps; }
 
-private:
-    typedef RefMap< sal_Int32, FunctionInfo >           OpCodeFuncMap;
-    typedef ::boost::shared_ptr< OpCodeFuncMap >        OpCodeFuncMapRef;
-    typedef ::boost::shared_ptr< OpCodeEntryVector >    OpCodeEntryVectorRef;
+    /** Calls the XFormulaParser::parseFormula() function of the API parser. */
+    ApiTokenSequence    parseFormula(
+                            const ::rtl::OUString& rFormula,
+                            const ::com::sun::star::table::CellAddress& rRefPos );
 
-    OpCodeFuncMapRef    mxOpCodeFuncs;      /// Maps API op-codes to function data.
-    FuncNameMapRef      mxExtProgFuncs;     /// Maps programmatical API function names to function data.
-    OpCodeEntryVectorRef mxParserMap;       /// OOXML token mapping for formula parser service.
+private:
+    ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser >
+                        mxParser;
+    PropertySet         maParserProps;
 };
 
 // formula contexts ===========================================================
@@ -606,10 +602,10 @@ private:
     ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaTokens > mxTokens;
 };
 
-// formula parser/formula compiler base class =================================
+// formula parser/printer base class for filters ==============================
 
 /** Base class for import formula parsers and export formula compilers. */
-class FormulaProcessorBase : public OpCodeProvider
+class FormulaProcessorBase : public OpCodeProvider, protected ApiOpCodes, public WorkbookHelper
 {
 public:
     explicit            FormulaProcessorBase( const WorkbookHelper& rHelper );
diff --git a/oox/inc/oox/xls/formulaparser.hxx b/oox/inc/oox/xls/formulaparser.hxx
index 2394f02..f992dc0 100644
--- a/oox/inc/oox/xls/formulaparser.hxx
+++ b/oox/inc/oox/xls/formulaparser.hxx
@@ -36,6 +36,69 @@
 namespace oox {
 namespace xls {
 
+// formula finalizer ==========================================================
+
+/** A generic formula token array finalizer.
+
+    After building a formula token array from alien binary file formats, or
+    parsing an XML formula string using the com.sun.star.sheet.FormulaParser
+    service, the token array is still not ready to be put into the spreadsheet
+    document. There may be functions with a wrong number of parameters (missing
+    but required parameters, or unsupported parameters) or intermediate tokens
+    used to encode references to macro functions or add-in functions. This
+    helper processes a passed token array and builds a new compatible token
+    array.
+
+    Derived classes may add more functionality by overwriting the virtual
+    functions.
+ */
+class FormulaFinalizer : public OpCodeProvider, protected ApiOpCodes
+{
+public:
+    explicit            FormulaFinalizer( const OpCodeProvider& rOpCodeProv );
+
+    /** Finalizes and returns the passed token array. */
+    ApiTokenSequence    finalizeTokenArray( const ApiTokenSequence& rTokens );
+
+protected:
+    /** Derived classed may try to find a function info struct from the passed
+        string extracted from an OPCODE_BAD token.
+
+        @param rTokenData  The string that has been found in an OPCODE_BAD
+            token preceding the function parentheses.
+     */
+    virtual const FunctionInfo* resolveBadFuncName( const ::rtl::OUString& rTokenData ) const;
+
+    /** Derived classed may try to find the name of a defined name with the
+        passed index extracted from an OPCODE_NAME token.
+
+        @param nTokenIndex  The index of the defined name that has been found
+            in an OPCODE_NAME token preceding the function parentheses.
+     */
+    virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
+
+private:
+    typedef ::std::vector< const ApiToken* > ParameterPosVector;
+
+    const FunctionInfo* getFunctionInfo( ApiToken& orFuncToken );
+    const FunctionInfo* getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken );
+
+    void                processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd );
+    const ApiToken*     processParameters( const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd );
+
+    bool                isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    const ApiToken*     findParameters( ParameterPosVector& rParams, const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
+    void                appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam );
+    void                appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount );
+
+    bool                appendFinalToken( const ApiToken& rToken );
+
+private:
+    ApiTokenVector      maTokens;
+};
+
 // ============================================================================
 
 class FormulaParserImpl;
@@ -63,7 +126,7 @@ public:
                             RecordInputStream& rStrm ) const;
 
     /** Imports and converts a BIFF token array from the passed stream.
-        @param pnFmlaSize  Size of the token array. If 0 is passed, reads
+        @param pnFmlaSize  Size of the token array. If null is passed, reads
         it from stream (1 byte in BIFF2, 2 bytes otherwise) first. */
     void                importFormula(
                             FormulaContext& rContext,
diff --git a/oox/inc/oox/xls/ooxformulaparser.hxx b/oox/inc/oox/xls/ooxformulaparser.hxx
new file mode 100644
index 0000000..97bad7e
--- /dev/null
+++ b/oox/inc/oox/xls/ooxformulaparser.hxx
@@ -0,0 +1,115 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: ooxformulaparser.hxx,v $
+ * $Revision: 1.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef OOX_XLS_OOXFORMULAPARSER_HXX
+#define OOX_XLS_OOXFORMULAPARSER_HXX
+
+#include <boost/shared_ptr.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XFilterFormulaParser.hpp>
+#include <cppuhelper/implbase3.hxx>
+
+namespace oox {
+namespace xls {
+
+class OOXMLFormulaParserImpl;
+class OOXMLFormulaPrinterImpl;
+
+// ============================================================================
+
+typedef ::cppu::WeakImplHelper3<
+    ::com::sun::star::lang::XServiceInfo,
+    ::com::sun::star::lang::XInitialization,
+    ::com::sun::star::sheet::XFilterFormulaParser > OOXMLFormulaParserBase;
+
+/** OOXML formula parser/compiler service for usage in ODF filters. */
+class OOXMLFormulaParser : public OOXMLFormulaParserBase
+{
+public:
+    explicit            OOXMLFormulaParser();
+    virtual             ~OOXMLFormulaParser();
+
+    // com.sun.star.lang.XServiceInfo interface -------------------------------
+
+    virtual ::rtl::OUString SAL_CALL
+                        getImplementationName() throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual sal_Bool SAL_CALL
+                        supportsService( const ::rtl::OUString& rService )
+                            throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL
+                        getSupportedServiceNames() throw( ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.lang.XInitialization interface ----------------------------
+
+    virtual void SAL_CALL initialize(
+                            const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rArgs )
+                            throw( ::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.sheet.XFilterFormulaParser interface ----------------------
+
+    virtual ::rtl::OUString SAL_CALL
+                        getSupportedNamespace()
+                            throw( ::com::sun::star::uno::RuntimeException );
+
+    // com.sun.star.sheet.XFormulaParser interface ----------------------------
+
+    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > SAL_CALL
+                        parseFormula(
+                            const ::rtl::OUString& rFormula,
+                            const ::com::sun::star::table::CellAddress& rReferencePos )
+                        throw( ::com::sun::star::uno::RuntimeException );
+
+    virtual ::rtl::OUString SAL_CALL
+                        printFormula(
+                            const ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken >& rTokens,
+                            const ::com::sun::star::table::CellAddress& rReferencePos )
+                        throw( ::com::sun::star::uno::RuntimeException );
+
+private:
+    typedef ::boost::shared_ptr< OOXMLFormulaParserImpl >   ParserImplRef;
+    typedef ::boost::shared_ptr< OOXMLFormulaPrinterImpl >  PrinterImplRef;
+
+    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >
+                        mxComponent;
+    ParserImplRef       mxParserImpl;       /// Implementation of import parser.
+    PrinterImplRef      mxPrinterImpl;      /// Implementation of export printer.
+};
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+
+#endif
+
diff --git a/oox/inc/oox/xls/workbookhelper.hxx b/oox/inc/oox/xls/workbookhelper.hxx
index daaba25..207b691 100644
--- a/oox/inc/oox/xls/workbookhelper.hxx
+++ b/oox/inc/oox/xls/workbookhelper.hxx
@@ -321,7 +321,7 @@ public:
 
     // converters -------------------------------------------------------------
 
-    /** Returns the import formula parser. */
+    /** Returns the import formula parser (import filter only!). */
     FormulaParser&      getFormulaParser() const;
     /** Returns the measurement unit converter. */
     UnitConverter&      getUnitConverter() const;
diff --git a/oox/source/core/facreg.cxx b/oox/source/core/facreg.cxx
index f1ead12..8d3846f 100644
--- a/oox/source/core/facreg.cxx
+++ b/oox/source/core/facreg.cxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2008 by Sun Microsystems, Inc.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -66,6 +66,7 @@ namespace oox {
     namespace shape { SERVICE( ShapeContextHandler ); }
     namespace shape { SERVICE( FastTokenHandlerService ); }
     namespace docprop { SERVICE2( OOXMLDocPropImportImpl ); }
+    namespace xls { SERVICE2( OOXMLFormulaParser ); }
 }
 
 //
@@ -108,6 +109,7 @@ OOX_DLLPUBLIC sal_Bool SAL_CALL component_writeInfo( void * , void * pRegistryKe
             WRITEINFO( ::oox::shape::ShapeContextHandler );
             WRITEINFO( ::oox::shape::FastTokenHandlerService );
             WRITEINFO( ::oox::docprop::OOXMLDocPropImportImpl );
+            WRITEINFO( ::oox::xls::OOXMLFormulaParser );
         }
         catch (registry::InvalidRegistryException &)
         {
@@ -147,7 +149,6 @@ OOX_DLLPUBLIC void * SAL_CALL component_getFactory( const sal_Char * pImplName,
 
         const sal_Int32 nImplNameLen = strlen( pImplName );
 
-        // impress oasis import
         SINGLEFACTORY( ::oox::core::FilterDetect )
         else SINGLEFACTORY( oox::ppt::PowerPointImport )
         else SINGLEFACTORY( ::oox::xls::BiffDetector )
@@ -156,6 +157,7 @@ OOX_DLLPUBLIC void * SAL_CALL component_getFactory( const sal_Char * pImplName,
         else SINGLEFACTORY( ::oox::shape::ShapeContextHandler)
         else SINGLEFACTORY( ::oox::shape::FastTokenHandlerService)
         else SINGLEFACTORY2( ::oox::docprop::OOXMLDocPropImportImpl )
+        else SINGLEFACTORY2( ::oox::xls::OOXMLFormulaParser )
 
         if( xFactory.is())
         {
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index 84c6f54..39cc9cf 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -288,7 +288,6 @@ Printable
 Protected
 Reference
 ReferenceDevice
-ReferencePosition
 RegularExpressions
 RelId
 RelativeHorizontalTabbarWidth
diff --git a/oox/source/xls/externallinkbuffer.cxx b/oox/source/xls/externallinkbuffer.cxx
index 8bc5e2f..5647752 100644
--- a/oox/source/xls/externallinkbuffer.cxx
+++ b/oox/source/xls/externallinkbuffer.cxx
@@ -750,15 +750,14 @@ void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl, const OUStr
     meLinkType = LINKTYPE_UNKNOWN;
     if( rTargetType == OOX_TARGETTYPE_EXTLINK )
     {
-    maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
+        maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
         if( maTargetUrl.getLength() > 0 )
             meLinkType = LINKTYPE_EXTERNAL;
     }
     else if( rTargetType == OOX_TARGETTYPE_LIBRARY )
     {
         meLinkType = LINKTYPE_LIBRARY;
-        if( rTargetUrl.equalsIgnoreAsciiCaseAscii( "EUROTOOL.XLA" ) || rTargetUrl.equalsIgnoreAsciiCaseAscii( "EUROTOOL.XLAM" ) )
-            meFuncLibType = FUNCLIB_EUROTOOL;
+        meFuncLibType = getFormulaParser().getFuncLibTypeFromLibraryName( rTargetUrl );
     }
     OSL_ENSURE( meLinkType != LINKTYPE_UNKNOWN, "ExternalLink::setExternalTargetUrl - empty target URL or unknown target type" );
 
diff --git a/oox/source/xls/formulabase.cxx b/oox/source/xls/formulabase.cxx
index 069dd75..00da5cd 100644
--- a/oox/source/xls/formulabase.cxx
+++ b/oox/source/xls/formulabase.cxx
@@ -34,6 +34,7 @@
 #include <rtl/ustrbuf.hxx>
 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
 #include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/AddressConvention.hpp>
 #include <com/sun/star/sheet/ReferenceFlags.hpp>
 #include <com/sun/star/sheet/SingleReference.hpp>
 #include <com/sun/star/sheet/ComplexReference.hpp>
@@ -41,9 +42,9 @@
 #include <com/sun/star/sheet/FormulaMapGroup.hpp>
 #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
 #include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
+#include <com/sun/star/sheet/XFormulaParser.hpp>
 #include <com/sun/star/sheet/XFormulaTokens.hpp>
 #include "properties.hxx"
-#include "oox/helper/propertyset.hxx"
 #include "oox/helper/recordinputstream.hxx"
 #include "oox/core/filterbase.hxx"
 #include "oox/xls/biffinputstream.hxx"
@@ -58,6 +59,7 @@ using ::com::sun::star::uno::Any;
 using ::com::sun::star::uno::Reference;
 using ::com::sun::star::uno::Sequence;
 using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::UNO_QUERY;
 using ::com::sun::star::uno::UNO_QUERY_THROW;
 using ::com::sun::star::table::CellAddress;
 using ::com::sun::star::table::CellRangeAddress;
@@ -294,9 +296,9 @@ static const FunctionData saFuncTableBiff2[] =
     { "SIN",                    "SIN",                  15,     15,     1,  1,  V, { V }, 0 },
     { "COS",                    "COS",                  16,     16,     1,  1,  V, { V }, 0 },
     { "TAN",                    "TAN",                  17,     17,     1,  1,  V, { V }, 0 },
-    { "COT",                    "TAN",                  17,     17,     1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
+    { "COT",                    0,                      17,     17,     1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
     { "ATAN",                   "ATAN",                 18,     18,     1,  1,  V, { V }, 0 },
-    { "ACOT",                   "ATAN",                 18,     18,     1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
+    { "ACOT",                   0,                      18,     18,     1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
     { "PI",                     "PI",                   19,     19,     0,  0,  V, {}, 0 },
     { "SQRT",                   "SQRT",                 20,     20,     1,  1,  V, { V }, 0 },
     { "EXP",                    "EXP",                  21,     21,     1,  1,  V, { V }, 0 },
@@ -457,11 +459,11 @@ static const FunctionData saFuncTableBiff3[] =
     { "SINH",                   "SINH",                 229,    229,    1,  1,  V, { V }, 0 },
     { "COSH",                   "COSH",                 230,    230,    1,  1,  V, { V }, 0 },
     { "TANH",                   "TANH",                 231,    231,    1,  1,  V, { V }, 0 },
-    { "COTH",                   "TANH",                 231,    231,    1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
+    { "COTH",                   0,                      231,    231,    1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
     { "ASINH",                  "ASINH",                232,    232,    1,  1,  V, { V }, 0 },
     { "ACOSH",                  "ACOSH",                233,    233,    1,  1,  V, { V }, 0 },
     { "ATANH",                  "ATANH",                234,    234,    1,  1,  V, { V }, 0 },
-    { "ACOTH",                  "ATANH",                234,    234,    1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
+    { "ACOTH",                  0,                      234,    234,    1,  1,  V, { V }, FUNCFLAG_EXPORTONLY },
     { "DGET",                   "DGET",                 235,    235,    3,  3,  V, { R }, 0 },
     { "INFO",                   "INFO",                 244,    244,    1,  1,  V, { V }, FUNCFLAG_VOLATILE }
 };
@@ -790,15 +792,35 @@ FuncInfoParamClassIterator& FuncInfoParamClassIterator::operator++()
 
 // function provider ==========================================================
 
-FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
-    mxFuncs( new FuncVector ),
-    mxOdfFuncs( new FuncNameMap ),
-    mxOoxFuncs( new FuncNameMap ),
-    mxOobFuncs( new FuncIdMap ),
-    mxBiffFuncs( new FuncIdMap ),
-    mxMacroFuncs( new FuncNameMap )
-{
-    OSL_ENSURE( bImportFilter, "FunctionProvider::FunctionProvider - need special handling for macro call functions" );
+struct FunctionProviderImpl
+{
+    typedef RefMap< OUString, FunctionInfo >    FuncNameMap;
+    typedef RefMap< sal_uInt16, FunctionInfo >  FuncIdMap;
+
+    FunctionInfoVector  maFuncs;            /// All function infos in one list.
+    FuncNameMap         maOdfFuncs;         /// Maps ODF function names to function data.
+    FuncNameMap         maOoxFuncs;         /// Maps OOXML function names to function data.
+    FuncIdMap           maOobFuncs;         /// Maps OOBIN function indexes to function data.
+    FuncIdMap           maBiffFuncs;        /// Maps BIFF function indexes to function data.
+    FuncNameMap         maMacroFuncs;       /// Maps macro function names to function data.
+
+    explicit            FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter );
+
+private:
+    /** Creates and inserts a function info struct from the passed function data. */
+    void                initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam );
+
+    /** Initializes the members from the passed function data list. */
+    void                initFuncs(
+                            const FunctionData* pBeg, const FunctionData* pEnd,
+                            sal_uInt8 nMaxParam, bool bImportFilter );
+};
+
+// ----------------------------------------------------------------------------
+
+FunctionProviderImpl::FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter )
+{
+    OSL_ENSURE( bImportFilter, "FunctionProviderImpl::FunctionProviderImpl - need special handling for macro call functions" );
     sal_uInt8 nMaxParam = 0;
     switch( eFilter )
     {
@@ -810,10 +832,10 @@ FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bIm
             nMaxParam = BIFF_MAX_PARAMCOUNT;
         break;
         case FILTER_UNKNOWN:
-            OSL_ENSURE( false, "FunctionProvider::FunctionProvider - invalid filter type" );
+            OSL_ENSURE( false, "FunctionProviderImpl::FunctionProviderImpl - invalid filter type" );
         break;
     }
-    OSL_ENSURE( eBiff != BIFF_UNKNOWN, "FunctionProvider::FunctionProvider - invalid BIFF type" );
+    OSL_ENSURE( eBiff != BIFF_UNKNOWN, "FunctionProviderImpl::FunctionProviderImpl - invalid BIFF type" );
 
     /*  Add functions supported in the current BIFF version only. Function
         tables from later BIFF versions may overwrite single functions from
@@ -832,38 +854,7 @@ FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bIm
         initFuncs( saFuncTableOox, STATIC_ARRAY_END( saFuncTableOox ), nMaxParam, bImportFilter );
 }
 
-FunctionProvider::~FunctionProvider()
-{
-}
-
-const FunctionInfo* FunctionProvider::getFuncInfoFromOdfFuncName( const OUString& rFuncName ) const
-{
-    return mxOdfFuncs->get( rFuncName ).get();
-}
-
-const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
-{
-    return mxOoxFuncs->get( rFuncName ).get();
-}
-
-const FunctionInfo* FunctionProvider::getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const
-{
-    return mxOobFuncs->get( nFuncId ).get();
-}
-
-const FunctionInfo* FunctionProvider::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
-{
-    return mxBiffFuncs->get( nFuncId ).get();
-}
-
-const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
-{
-    return mxMacroFuncs->get( rFuncName ).get();
-}
-
-// private --------------------------------------------------------------------
-
-void FunctionProvider::initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam )
+void FunctionProviderImpl::initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam )
 {
     // create a function info object
     FunctionInfoRef xFuncInfo( new FunctionInfo );
@@ -895,38 +886,122 @@ void FunctionProvider::initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxPa
     setFlag( xFuncInfo->mnBiffFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
 
     // insert the function info into the member maps
-    mxFuncs->push_back( xFuncInfo );
+    maFuncs.push_back( xFuncInfo );
     if( xFuncInfo->maOdfFuncName.getLength() > 0 )
-        (*mxOdfFuncs)[ xFuncInfo->maOdfFuncName ] = xFuncInfo;
+        maOdfFuncs[ xFuncInfo->maOdfFuncName ] = xFuncInfo;
     if( xFuncInfo->maOoxFuncName.getLength() > 0 )
-        (*mxOoxFuncs)[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
+        maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
     if( xFuncInfo->mnOobFuncId != NOID )
-        (*mxOobFuncs)[ xFuncInfo->mnOobFuncId ] = xFuncInfo;
+        maOobFuncs[ xFuncInfo->mnOobFuncId ] = xFuncInfo;
     if( xFuncInfo->mnBiffFuncId != NOID )
-        (*mxBiffFuncs)[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
+        maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
     if( xFuncInfo->maBiffMacroName.getLength() > 0 )
-        (*mxMacroFuncs)[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
+        maMacroFuncs[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
 }
 
-void FunctionProvider::initFuncs( const FunctionData* pBeg, const FunctionData* pEnd, sal_uInt8 nMaxParam, bool bImportFilter )
+void FunctionProviderImpl::initFuncs( const FunctionData* pBeg, const FunctionData* pEnd, sal_uInt8 nMaxParam, bool bImportFilter )
 {
     for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
         if( pIt->isSupported( bImportFilter ) )
             initFunc( *pIt, nMaxParam );
 }
 
+// ----------------------------------------------------------------------------
+
+FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
+    mxFuncImpl( new FunctionProviderImpl( eFilter, eBiff, bImportFilter ) )
+{
+}
+
+FunctionProvider::~FunctionProvider()
+{
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOdfFuncName( const OUString& rFuncName ) const
+{
+    return mxFuncImpl->maOdfFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
+{
+    return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromOobFuncId( sal_uInt16 nFuncId ) const
+{
+    return mxFuncImpl->maOobFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
+{
+    return mxFuncImpl->maBiffFuncs.get( nFuncId ).get();
+}
+
+const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
+{
+    return mxFuncImpl->maMacroFuncs.get( rFuncName ).get();
+}
+
+FunctionLibraryType FunctionProvider::getFuncLibTypeFromLibraryName( const OUString& rLibraryName ) const
+{
+#define OOX_XLS_IS_LIBNAME( libname, basename ) (libname.equalsIgnoreAsciiCaseAscii( basename ".XLA" ) || libname.equalsIgnoreAsciiCaseAscii( basename ".XLAM" ))
+
+    // the EUROTOOL add-in containing the EUROCONVERT function
+    if( OOX_XLS_IS_LIBNAME( rLibraryName, "EUROTOOL" ) )
+        return FUNCLIB_EUROTOOL;
+
+#undef OOX_XLS_IS_LIBNAME
+
+    // default: unknown library
+    return FUNCLIB_UNKNOWN;
+}
+
+const FunctionInfoVector& FunctionProvider::getFuncs() const
+{
+    return mxFuncImpl->maFuncs;
+}
+
 // op-code and function provider ==============================================
 
-OpCodeProvider::OpCodeProvider( const WorkbookHelper& rHelper ) :
-    FunctionProvider( rHelper.getFilterType(), rHelper.getBiff(), rHelper.getBaseFilter().isImportFilter() ),
-    WorkbookHelper( rHelper ),
-    mxOpCodeFuncs( new OpCodeFuncMap ),
-    mxExtProgFuncs( new FuncNameMap ),
-    mxParserMap( new OpCodeEntryVector )
+struct OpCodeProviderImpl : public ApiOpCodes
 {
-    try
+    typedef RefMap< sal_Int32, FunctionInfo >       OpCodeFuncMap;
+    typedef RefMap< OUString, FunctionInfo >        FuncNameMap;
+    typedef ::std::vector< FormulaOpCodeMapEntry >  OpCodeEntryVector;
+
+    OpCodeFuncMap       maOpCodeFuncs;      /// Maps API function op-codes to function data.
+    FuncNameMap         maExtProgFuncs;     /// Maps programmatical API function names to function data.
+    OpCodeEntryVector   maParserMap;        /// OOXML token mapping for formula parser service.
+
+    explicit            OpCodeProviderImpl(
+                            const FunctionInfoVector& rFuncInfos,
+                            const Reference< XMultiServiceFactory >& rxFactory );
+
+private:
+    typedef ::std::map< OUString, ApiToken >    ApiTokenMap;
+    typedef Sequence< FormulaOpCodeMapEntry >   OpCodeEntrySequence;
+
+    static bool         fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+    static bool         fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
+    bool                fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const;
+
+    static bool         initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
+    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName );
+    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName );
+    bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
+
+    bool                initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
+    bool                initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos );
+};
+
+// ----------------------------------------------------------------------------
+
+OpCodeProviderImpl::OpCodeProviderImpl( const FunctionInfoVector& rFuncInfos,
+        const Reference< XMultiServiceFactory >& rxFactory )
+{
+    if( rxFactory.is() ) try
     {
-        Reference< XFormulaOpCodeMapper > xMapper( getDocumentFactory()->createInstance(
+        Reference< XFormulaOpCodeMapper > xMapper( rxFactory->createInstance(
             CREATE_OUSTRING( "com.sun.star.sheet.FormulaOpCodeMapper" ) ), UNO_QUERY_THROW );
 
         // op-codes provided as attributes
@@ -985,61 +1060,22 @@ OpCodeProvider::OpCodeProvider( const WorkbookHelper& rHelper ) :
             initOpCode( OPCODE_RANGE,         aTokenMap, ':',  ':'  ) &&
             // functions
             fillFuncTokenMaps( aTokenMap, aExtFuncTokenMap, aEntrySeq, xMapper ) &&
-            initFuncOpCodes( aTokenMap, aExtFuncTokenMap ) &&
+            initFuncOpCodes( aTokenMap, aExtFuncTokenMap, rFuncInfos ) &&
             initOpCode( OPCODE_DDE,           aTokenMap, "DDE", 0 );
 
-        OSL_ENSURE( bIsValid, "OpCodeProvider::OpCodeProvider - opcodes not initialized" );
+        OSL_ENSURE( bIsValid, "OpCodeProviderImpl::OpCodeProviderImpl - opcodes not initialized" );
         (void)bIsValid;
 
         // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
-        OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProvider::OpCodeProvider - need opcode mapping for OPCODE_PLUS_SIGN" );
+        OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProviderImpl::OpCodeProviderImpl - need opcode mapping for OPCODE_PLUS_SIGN" );
     }
     catch( Exception& )
     {
-        OSL_ENSURE( false, "OpCodeProvider::OpCodeProvider - cannot receive formula opcode mapper" );
-    }
-}
-
-OpCodeProvider::~OpCodeProvider()
-{
-}
-
-const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
-{
-    const FunctionInfo* pFuncInfo = 0;
-    if( (rToken.OpCode == OPCODE_EXTERNAL) && rToken.Data.hasValue() )
-    {
-        OUString aProgFuncName;
-        if( rToken.Data >>= aProgFuncName )
-            pFuncInfo = mxExtProgFuncs->get( aProgFuncName ).get();
-    }
-    else if( (rToken.OpCode == OPCODE_MACRO) && rToken.Data.hasValue() )
-    {
-        OUString aMacroName;
-        if( rToken.Data >>= aMacroName )
-            pFuncInfo = getFuncInfoFromMacroName( aMacroName );
-    }
-    else if( (rToken.OpCode == OPCODE_BAD) && rToken.Data.hasValue() )
-    {
-        OUString aOoxFuncName;
-        if( rToken.Data >>= aOoxFuncName )
-            pFuncInfo = getFuncInfoFromOoxFuncName( aOoxFuncName );
-    }
-    else
-    {
-        pFuncInfo = mxOpCodeFuncs->get( rToken.OpCode ).get();
+        OSL_ENSURE( false, "OpCodeProviderImpl::OpCodeProviderImpl - cannot receive formula opcode mapper" );
     }
-    return pFuncInfo;
-}
-
-Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
-{
-    return ContainerHelper::vectorToSequence( *mxParserMap );
 }
 
-// private --------------------------------------------------------------------
-
-bool OpCodeProvider::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
+bool OpCodeProviderImpl::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
         const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
 {
     try
@@ -1053,7 +1089,7 @@ bool OpCodeProvider::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
     return false;
 }
 
-bool OpCodeProvider::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
+bool OpCodeProviderImpl::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
         const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
 {
     orTokenMap.clear();
@@ -1067,7 +1103,7 @@ bool OpCodeProvider::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence&
     return orEntrySeq.hasElements();
 }
 
-bool OpCodeProvider::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
+bool OpCodeProviderImpl::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
 {
     orIntFuncTokenMap.clear();
     orExtFuncTokenMap.clear();
@@ -1081,7 +1117,7 @@ bool OpCodeProvider::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiToken
     return orEntrySeq.hasElements();
 }
 
-bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
 {
     if( (0 <= nSpecialId) && (nSpecialId < rEntrySeq.getLength()) )
     {
@@ -1089,12 +1125,12 @@ bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence
         return true;
     }
     OSL_ENSURE( false,
-        OStringBuffer( "OpCodeProvider::initOpCode - opcode for special offset " ).
+        OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for special offset " ).
         append( nSpecialId ).append( " not found" ).getStr() );
     return false;
 }
 
-bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
 {
     ApiTokenMap::const_iterator aIt = rTokenMap.find( rOdfName );
     if( aIt != rTokenMap.end() )
@@ -1105,32 +1141,32 @@ bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rToken
             FormulaOpCodeMapEntry aEntry;
             aEntry.Name = rOoxName;
             aEntry.Token.OpCode = ornOpCode;
-            mxParserMap->push_back( aEntry );
+            maParserMap.push_back( aEntry );
         }
         return true;
     }
     OSL_ENSURE( false,
-        OStringBuffer( "OpCodeProvider::initOpCode - opcode for \"" ).
+        OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for \"" ).
         append( OUStringToOString( rOdfName, RTL_TEXTENCODING_ASCII_US ) ).
         append( "\" not found" ).getStr() );
     return false;
 }
 
-bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName )
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName )
 {
     OUString aOoxName;
     if( pcOoxName ) aOoxName = OUString::createFromAscii( pcOoxName );
     return initOpCode( ornOpCode, rTokenMap, OUString::createFromAscii( pcOdfName ), aOoxName );
 }
 
-bool OpCodeProvider::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
+bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
 {
     OUString aOoxName;
     if( cOoxName ) aOoxName = OUString( cOoxName );
     return initOpCode( ornOpCode, rTokenMap, OUString( cOdfName ), aOoxName );
 }
 
-bool OpCodeProvider::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
+bool OpCodeProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
 {
     bool bIsValid = false;
     if( orFuncInfo.maOdfFuncName.getLength() > 0 )
@@ -1142,10 +1178,9 @@ bool OpCodeProvider::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap
             bIsValid =
                 (orFuncInfo.mnApiOpCode >= 0) &&
                 (orFuncInfo.mnApiOpCode != OPCODE_UNKNOWN) &&
-                (orFuncInfo.mnApiOpCode != OPCODE_NONAME) &&
-                (orFuncInfo.maOoxFuncName.getLength() > 0);
+                (orFuncInfo.mnApiOpCode != OPCODE_NONAME);
             OSL_ENSURE( bIsValid,
-                OStringBuffer( "OpCodeProvider::initFuncOpCode - no valid opcode or missing OOX function name for ODF function \"" ).
+                OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no valid opcode for ODF function \"" ).
                 append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
                 append( '"' ).getStr() );
 
@@ -1153,18 +1188,19 @@ bool OpCodeProvider::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap
             {
                 bIsValid = (aIt->second.Data >>= orFuncInfo.maExtProgName) && (orFuncInfo.maExtProgName.getLength() > 0);
                 OSL_ENSURE( bIsValid,
-                    OStringBuffer( "OpCodeProvider::initFuncOpCode - no programmatical name for external function \"" ).
+                    OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no programmatical name for external function \"" ).
                     append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
                     append( '"' ).getStr() );
             }
 
-            if( bIsValid )
+            // add to parser map, if OOX function name exists
+            if( bIsValid && (orFuncInfo.maOoxFuncName.getLength() > 0) )
             {
                 // create the parser map entry
                 FormulaOpCodeMapEntry aEntry;
                 aEntry.Name = orFuncInfo.maOoxFuncName;
                 aEntry.Token = aIt->second;
-                mxParserMap->push_back( aEntry );
+                maParserMap.push_back( aEntry );
             }
         }
     }
@@ -1184,10 +1220,10 @@ bool OpCodeProvider::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap
     return bIsValid;
 }
 
-bool OpCodeProvider::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap )
+bool OpCodeProviderImpl::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos )
 {
     bool bIsValid = true;
-    for( FuncVector::const_iterator aIt = getFuncs().begin(), aEnd = getFuncs().end(); aIt != aEnd; ++aIt )
+    for( FunctionInfoVector::const_iterator aIt = rFuncInfos.begin(), aEnd = rFuncInfos.end(); aIt != aEnd; ++aIt )
     {
         FunctionInfoRef xFuncInfo = *aIt;
         // set API opcode from ODF function name
@@ -1196,14 +1232,85 @@ bool OpCodeProvider::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const
         if( xFuncInfo->mnApiOpCode != OPCODE_NONAME )
         {
             if( (xFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (xFuncInfo->maExtProgName.getLength() > 0) )
-                (*mxExtProgFuncs)[ xFuncInfo->maExtProgName ] = xFuncInfo;
+                maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
             else
-                (*mxOpCodeFuncs)[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
+                maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
         }
     }
     return bIsValid;
 }
 
+// ----------------------------------------------------------------------------
+
+OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxFactory,
+        FilterType eFilter, BiffType eBiff, bool bImportFilter ) :
+    FunctionProvider( eFilter, eBiff, bImportFilter ),
+    mxOpCodeImpl( new OpCodeProviderImpl( getFuncs(), rxFactory ) )
+{
+}
+
+OpCodeProvider::~OpCodeProvider()
+{
+}
+
+const ApiOpCodes& OpCodeProvider::getOpCodes() const
+{
+    return *mxOpCodeImpl;
+}
+
+const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
+{
+    const FunctionInfo* pFuncInfo = 0;
+    if( (rToken.OpCode == mxOpCodeImpl->OPCODE_EXTERNAL) && rToken.Data.has< OUString >() )
+        pFuncInfo = mxOpCodeImpl->maExtProgFuncs.get( rToken.Data.get< OUString >() ).get();
+    else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_MACRO) && rToken.Data.has< OUString >() )
+        pFuncInfo = getFuncInfoFromMacroName( rToken.Data.get< OUString >() );
+    else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_BAD) && rToken.Data.has< OUString >() )
+        pFuncInfo = getFuncInfoFromOoxFuncName( rToken.Data.get< OUString >() );
+    else
+        pFuncInfo = mxOpCodeImpl->maOpCodeFuncs.get( rToken.OpCode ).get();
+    return pFuncInfo;
+}
+
+Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
+{
+    return ContainerHelper::vectorToSequence( mxOpCodeImpl->maParserMap );
+}
+
+// API formula parser wrapper =================================================
+
+ApiParserWrapper::ApiParserWrapper(
+        const Reference< XMultiServiceFactory >& rxFactory, const OpCodeProvider& rOpCodeProv ) :
+    OpCodeProvider( rOpCodeProv )
+{
+    if( rxFactory.is() ) try
+    {
+        mxParser.set( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.sheet.FormulaParser" ) ), UNO_QUERY_THROW );
+    }
+    catch( Exception& )
+    {
+    }
+    OSL_ENSURE( mxParser.is(), "ApiParserWrapper::ApiParserWrapper - cannot create API formula parser object" );
+    maParserProps.set( mxParser );
+    maParserProps.setProperty( PROP_CompileEnglish, true );
+    maParserProps.setProperty( PROP_FormulaConvention, ::com::sun::star::sheet::AddressConvention::XL_OOX );
+    maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
+    maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
+}
+
+ApiTokenSequence ApiParserWrapper::parseFormula( const OUString& rFormula, const CellAddress& rRefPos )
+{
+    ApiTokenSequence aTokenSeq;
+    if( mxParser.is() ) try
+    {
+        aTokenSeq = mxParser->parseFormula( rFormula, rRefPos );
+    }
+    catch( Exception& )
+    {
+    }
+    return aTokenSeq;
+}
+
 // formula contexts ===========================================================
 
 FormulaContext::FormulaContext( bool bRelativeAsOffset, bool b2dRefsAs3dRefs, bool bAllowNulChars ) :
@@ -1249,7 +1356,7 @@ void SimpleFormulaContext::setTokens( const ApiTokenSequence& rTokens )
     mxTokens->setTokens( rTokens );
 }
 
-// formula parser/formula compiler base class =================================
+// formula parser/printer base class for filters ==============================
 
 namespace {
 
@@ -1321,7 +1428,9 @@ TokenToRangeListState lclProcessClose( sal_Int32& ornParenLevel )
 // ----------------------------------------------------------------------------
 
 FormulaProcessorBase::FormulaProcessorBase( const WorkbookHelper& rHelper ) :
-    OpCodeProvider( rHelper )
+    OpCodeProvider( rHelper.getDocumentFactory(), rHelper.getFilterType(), rHelper.getBiff(), rHelper.getBaseFilter().isImportFilter() ),
+    ApiOpCodes( getOpCodes() ),
+    WorkbookHelper( rHelper )
 {
 }
 
diff --git a/oox/source/xls/formulaparser.cxx b/oox/source/xls/formulaparser.cxx
index 4183cb6..d2818ff 100644
--- a/oox/source/xls/formulaparser.cxx
+++ b/oox/source/xls/formulaparser.cxx
@@ -30,16 +30,12 @@
 
 #include "oox/xls/formulaparser.hxx"
 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
-#include <com/sun/star/sheet/AddressConvention.hpp>
 #include <com/sun/star/sheet/ComplexReference.hpp>
 #include <com/sun/star/sheet/ExternalReference.hpp>
 #include <com/sun/star/sheet/FormulaToken.hpp>
 #include <com/sun/star/sheet/ReferenceFlags.hpp>
 #include <com/sun/star/sheet/SingleReference.hpp>
-#include <com/sun/star/sheet/XFormulaParser.hpp>
 #include "properties.hxx"
-#include "oox/helper/containerhelper.hxx"
-#include "oox/helper/propertyset.hxx"
 #include "oox/helper/recordinputstream.hxx"
 #include "oox/core/filterbase.hxx"
 #include "oox/xls/addressconverter.hxx"
@@ -78,12 +74,351 @@ sal_uInt16 lclReadFmlaSize( BiffInputStream& rStrm, BiffType eBiff, const sal_uI
 
 } // namespace
 
+// formula finalizer ==========================================================
+
+FormulaFinalizer::FormulaFinalizer( const OpCodeProvider& rOpCodeProv ) :
+    OpCodeProvider( rOpCodeProv ),
+    ApiOpCodes( getOpCodes() )
+{
+    maTokens.reserve( 0x2000 );
+}
+
+ApiTokenSequence FormulaFinalizer::finalizeTokenArray( const ApiTokenSequence& rTokens )
+{
+    maTokens.clear();
+    if( rTokens.hasElements() )
+    {
+        const ApiToken* pToken = rTokens.getConstArray();
+        processTokens( pToken, pToken + rTokens.getLength() );
+    }
+    return ContainerHelper::vectorToSequence( maTokens );
+}
+
+const FunctionInfo* FormulaFinalizer::resolveBadFuncName( const OUString& ) const
+{
+    return 0;
+}
+
+OUString FormulaFinalizer::resolveDefinedName( sal_Int32 ) const
+{
+    return OUString();
+}
+
+const FunctionInfo* FormulaFinalizer::getFunctionInfo( ApiToken& orFuncToken )
+{
+    // first, try to find a regular function info from token op-code
+    if( const FunctionInfo* pRegFuncInfo = getFuncInfoFromApiToken( orFuncToken ) )
+        return pRegFuncInfo;
+
+    // try to recognize a function from an external library
+    if( (orFuncToken.OpCode == OPCODE_BAD) && orFuncToken.Data.has< OUString >() )
+    {
+        // virtual call to resolveBadFuncName()
+        if( const FunctionInfo* pLibFuncInfo = resolveBadFuncName( orFuncToken.Data.get< OUString >() ) )
+        {
+            // write function op-code to the OPCODE_BAD token
+            orFuncToken.OpCode = pLibFuncInfo->mnApiOpCode;
+            // if it is an external function, insert programmatic function name
+            if( (orFuncToken.OpCode == OPCODE_EXTERNAL) && (pLibFuncInfo->maExtProgName.getLength() > 0) )
+                orFuncToken.Data <<= pLibFuncInfo->maExtProgName;
+            else
+                orFuncToken.Data.clear();   // clear string from OPCODE_BAD
+            return pLibFuncInfo;
+        }
+    }
+
+    // no success - return null
+    return 0;
+
+}
+
+const FunctionInfo* FormulaFinalizer::getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken )
+{
+    // try to resolve the passed token to a supported sheet function
+    if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
+    {
+        orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
+        // programmatic add-in function name
+        if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
+            orFuncToken.Data <<= pFuncInfo->maExtProgName;
+        // name of unsupported function, convert to OPCODE_BAD to preserve the name
+        else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && (pFuncInfo->maOoxFuncName.getLength() > 0) )
+            orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
+        return pFuncInfo;
+    }
+
+    // macro call or unknown function name, move data to function token
+    if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
+        orFuncToken = rECToken;
+
+    // defined name used as function call, convert to OPCODE_BAD to preserve the name
+    if( (rECToken.OpCode == OPCODE_NAME) && rECToken.Data.has< sal_Int32 >() )
+    {
+        OUString aDefName = resolveDefinedName( rECToken.Data.get< sal_Int32 >() );
+        if( aDefName.getLength() > 0 )
+        {
+            orFuncToken.OpCode = OPCODE_BAD;
+            orFuncToken.Data <<= aDefName;
+        }
+    }
+
+    return 0;
+}
+
+void FormulaFinalizer::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+    while( pToken < pTokenEnd )
+    {
+        // push the current token into the vector
+        bool bValid = appendFinalToken( *pToken );
+        // try to process a function
+        if( const FunctionInfo* pFuncInfo = bValid ? getFunctionInfo( maTokens.back() ) : 0 )
+            pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
+        // otherwise, go to next token
+        else
+            ++pToken;
+    }
+}
+
+const ApiToken* FormulaFinalizer::processParameters(
+        const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
+{
+    // remember position of the token containing the function op-code
+    size_t nFuncNameIdx = maTokens.size() - 1;
+
+    // process a function, if an OPCODE_OPEN token is following
+    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::processParameters - OPCODE_OPEN expected" );
+    if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
+    {
+        // append the OPCODE_OPEN token to the vector
+        maTokens.append( OPCODE_OPEN );
+
+        // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
+        ParameterPosVector aParams;
+        pToken = findParameters( aParams, pToken, pTokenEnd );
+        OSL_ENSURE( aParams.size() >= 2, "FormulaFinalizer::processParameters - missing tokens" );
+        size_t nParamCount = aParams.size() - 1;
+
+        if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
+        {
+            /*  Empty pair of parentheses -> function call without parameters,
+                process parameter, there might be spaces between parentheses. */
+            processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
+        }
+        else
+        {
+            const FunctionInfo* pRealFuncInfo = &rFuncInfo;
+            ParameterPosVector::const_iterator aPosIt = aParams.begin();
+
+            /*  Preprocess EXTERN.CALL functions. The actual function name is
+                contained as reference to a defined name in the first (hidden)
+                parameter. */
+            if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
+            {
+                ApiToken& rFuncToken = maTokens[ nFuncNameIdx ];
+                rFuncToken.OpCode = OPCODE_NONAME;
+
+                // try to initialize function token from first parameter
+                if( const ApiToken* pECToken = getSingleToken( *aPosIt + 1, *(aPosIt + 1) ) )
+                    if( const FunctionInfo* pECFuncInfo = getExternCallInfo( rFuncToken, *pECToken ) )
+                        pRealFuncInfo = pECFuncInfo;
+
+                /*  On success (something has been inserted into rFuncToken),
+                    skip the first parameter. */
+                if( rFuncToken.OpCode != OPCODE_NONAME )
+                {
+                    --nParamCount;
+                    ++aPosIt;
+                }
+            }
+
+            // process all parameters
+            FuncInfoParamClassIterator aClassIt( *pRealFuncInfo );
+            size_t nLastValidSize = maTokens.size();
+            size_t nLastValidCount = 0;
+            for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aClassIt )
+            {
+                // add embedded Calc-only parameters
+                if( aClassIt.isCalcOnlyParam() )
+                {
+                    appendCalcOnlyParameter( *pRealFuncInfo, nParam );
+                    while( aClassIt.isCalcOnlyParam() ) ++aClassIt;
+                }
+
+                const ApiToken* pParamBegin = *aPosIt + 1;
+                const ApiToken* pParamEnd = *(aPosIt + 1);
+                bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
+
+                if( !aClassIt.isExcelOnlyParam() )
+                {
+                    // replace empty second and third parameter in IF function with zeros
+                    if( (pRealFuncInfo->mnOobFuncId == OOBIN_FUNC_IF) && ((nParam == 1) || (nParam == 2)) && bIsEmpty )
+                    {
+                        maTokens.append< double >( OPCODE_PUSH, 0.0 );
+                        bIsEmpty = false;
+                    }
+                    else
+                    {
+                        // process all tokens of the parameter
+                        processTokens( pParamBegin, pParamEnd );
+                    }
+                    // append parameter separator token
+                    maTokens.append( OPCODE_SEP );
+                }
+
+                /*  #84453# Update size of new token sequence with valid parameters
+                    to be able to remove trailing optional empty parameters. */
+                if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
+                {
+                    nLastValidSize = maTokens.size();
+                    nLastValidCount = nParam + 1;
+                }
+            }
+
+            // #84453# remove trailing optional empty parameters
+            maTokens.resize( nLastValidSize );
+
+            // add trailing Calc-only parameters
+            if( aClassIt.isCalcOnlyParam() )
+                appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
+
+            // add optional parameters that are required in Calc
+            appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
+
+            // remove last parameter separator token
+            if( maTokens.back().OpCode == OPCODE_SEP )
+                maTokens.pop_back();
+        }
+
+        /*  Append the OPCODE_CLOSE token to the vector, but only if there is
+            no OPCODE_BAD token at the end, this token already contains the
+            trailing closing parentheses. */
+        if( (pTokenEnd - 1)->OpCode != OPCODE_BAD )
+            maTokens.append( OPCODE_CLOSE );
+    }
+
+    /*  Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
+        if no matching add-in function was found. */
+    ApiToken& rFuncNameToken = maTokens[ nFuncNameIdx ];
+    if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
+        rFuncNameToken.OpCode = OPCODE_NONAME;
+
+    return pToken;
+}
+
+bool FormulaFinalizer::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+    if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
+    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+    return pToken == pTokenEnd;
+}
+
+const ApiToken* FormulaFinalizer::getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+    const ApiToken* pSingleToken = 0;
+    // skip leading whitespace tokens
+    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+    // remember first non-whitespace token
+    if( pToken < pTokenEnd ) pSingleToken = pToken++;
+    // skip trailing whitespace tokens
+    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
+    // return null, if other non-whitespace tokens follow
+    return (pToken == pTokenEnd) ? pSingleToken : 0;
+}
+
+const ApiToken* FormulaFinalizer::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+    // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
+    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
+    ++pToken;
+    while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
+    {
+        if( pToken->OpCode == OPCODE_OPEN )
+            pToken = skipParentheses( pToken, pTokenEnd );
+        else
+            ++pToken;
+    }
+    // skip the OPCODE_CLOSE token
+    OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
+    return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+const ApiToken* FormulaFinalizer::findParameters( ParameterPosVector& rParams,
+        const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+{
+    // push position of OPCODE_OPEN
+    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::findParameters - OPCODE_OPEN expected" );
+    rParams.push_back( pToken++ );
+
+    // find positions of parameter separators
+    while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
+    {
+        if( pToken->OpCode == OPCODE_OPEN )
+            pToken = skipParentheses( pToken, pTokenEnd );
+        else if( pToken->OpCode == OPCODE_SEP )
+            rParams.push_back( pToken++ );
+        else
+            ++pToken;
+    }
+
+    // push position of OPCODE_CLOSE
+    OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaFinalizer::findParameters - OPCODE_CLOSE expected" );
+    rParams.push_back( pToken );
+    return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
+}
+
+void FormulaFinalizer::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
+{
+    (void)nParam;   // prevent 'unused' warning
+    switch( rFuncInfo.mnOobFuncId )
+    {
+        case OOBIN_FUNC_FLOOR:
+        case OOBIN_FUNC_CEILING:
+            OSL_ENSURE( nParam == 2, "FormulaFinalizer::appendCalcOnlyParameter - unexpected parameter index" );
+            maTokens.append< double >( OPCODE_PUSH, 1.0 );
+            maTokens.append( OPCODE_SEP );
+        break;
+    }
+}
+
+void FormulaFinalizer::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
+{
+    switch( rFuncInfo.mnOobFuncId )
+    {
+        case OOBIN_FUNC_WEEKNUM:
+            if( nParamCount == 1 )
+            {
+                maTokens.append< double >( OPCODE_PUSH, 1.0 );
+                maTokens.append( OPCODE_SEP );
+            }
+        break;
+    }
+}
+
+bool FormulaFinalizer::appendFinalToken( const ApiToken& rToken )
+{
+    // replace OPCODE_MACRO without macro name with #NAME? error code
+    bool bValid = (rToken.OpCode != OPCODE_MACRO) || rToken.Data.hasValue();
+    if( bValid )
+    {
+        maTokens.push_back( rToken );
+    }
+    else
+    {
+        maTokens.append( OPCODE_ARRAY_OPEN );
+        maTokens.append( OPCODE_PUSH, BiffHelper::calcDoubleFromError( BIFF_ERR_NAME ) );
+        maTokens.append( OPCODE_ARRAY_CLOSE );
+    }
+    return bValid;
+}
+
 // parser implementation base =================================================
 
-class FormulaParserImpl : public OpCodeProvider
+class FormulaParserImpl : public FormulaFinalizer, public WorkbookHelper
 {
 public:
-    explicit            FormulaParserImpl( const OpCodeProvider& rOpCodeProv );
+    explicit            FormulaParserImpl( const FormulaParser& rParent );
 
     /** Converts an XML formula string. */
     virtual void        importOoxFormula(
@@ -208,23 +543,11 @@ private:
     void                convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
     void                convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
 
+private:
     // finalize token sequence ------------------------------------------------
 
-    typedef ::std::vector< const ApiToken* > ParameterPosVector;
-
-    void                processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd );
-    const ApiToken*     processParameters( const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd );
-
-    const FunctionInfo* getFuncInfoFromLibFuncName( const ApiToken& rToken ) const;
-    bool                isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
-    const ApiToken*     getExternCallToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
-    const FunctionInfo* convertExternCallParam( ApiToken& orFuncToken, const ApiToken& rECToken ) const;
-    const ApiToken*     skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
-    const ApiToken*     findParameters( ParameterPosVector& rParams, const ApiToken* pToken, const ApiToken* pTokenEnd ) const;
-    void                appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam );
-    void                appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount );
-
-    void                appendFinalToken( const ApiToken& rToken );
+    virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
+    virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
 
 protected:
     const sal_Int32     mnMaxApiCol;                /// Maximum column index in own document.
@@ -246,12 +569,13 @@ private:
 
 // ----------------------------------------------------------------------------
 
-FormulaParserImpl::FormulaParserImpl( const OpCodeProvider& rOpCodeProv ) :
-    OpCodeProvider( rOpCodeProv ),
-    mnMaxApiCol( rOpCodeProv.getAddressConverter().getMaxApiAddress().Column ),
-    mnMaxApiRow( rOpCodeProv.getAddressConverter().getMaxApiAddress().Row ),
-    mnMaxXlsCol( rOpCodeProv.getAddressConverter().getMaxXlsAddress().Column ),
-    mnMaxXlsRow( rOpCodeProv.getAddressConverter().getMaxXlsAddress().Row ),
+FormulaParserImpl::FormulaParserImpl( const FormulaParser& rParent ) :
+    FormulaFinalizer( rParent ),
+    WorkbookHelper( rParent ),
+    mnMaxApiCol( rParent.getAddressConverter().getMaxApiAddress().Column ),
+    mnMaxApiRow( rParent.getAddressConverter().getMaxApiAddress().Row ),
+    mnMaxXlsCol( rParent.getAddressConverter().getMaxXlsAddress().Column ),
+    mnMaxXlsRow( rParent.getAddressConverter().getMaxXlsAddress().Row ),
     mpContext( 0 )
 {
     // reserve enough space to make resize(), push_back() etc. cheap
@@ -303,11 +627,9 @@ void FormulaParserImpl::initializeImport( FormulaContext& rContext )
 
 void FormulaParserImpl::finalizeImport( const ApiTokenSequence& rTokens )
 {
-    maTokenStorage.clear();
-    const ApiToken* pToken = rTokens.getConstArray();
-    processTokens( pToken, pToken + rTokens.getLength() );
-    if( !maTokenStorage.empty() )
-        mpContext->setTokens( ContainerHelper::vectorToSequence( maTokenStorage ) );
+    ApiTokenSequence aFinalTokens = finalizeTokenArray( rTokens );
+    if( aFinalTokens.hasElements() )
+        mpContext->setTokens( aFinalTokens );
 }
 
 void FormulaParserImpl::finalizeImport()
@@ -885,342 +1207,34 @@ void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const Li
 
 // finalize token sequence ----------------------------------------------------
 
-void FormulaParserImpl::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
-{
-    while( pToken < pTokenEnd )
-    {
-        // push the current token into the vector
-        appendFinalToken( *pToken );
-        const FunctionInfo* pFuncInfo;
-        // try to process a function
-        if( (pFuncInfo = getFuncInfoFromApiToken( *pToken )) != 0 )
-        {
-            pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
-        }
-        // try to process a function from an external library
-        else if( (pFuncInfo = getFuncInfoFromLibFuncName( *pToken )) != 0 )
-        {
-            ApiToken& rFuncToken = maTokenStorage.back();
-            rFuncToken.OpCode = pFuncInfo->mnApiOpCode;
-            if( (rFuncToken.OpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
-                rFuncToken.Data <<= pFuncInfo->maExtProgName;
-            else
-                rFuncToken.Data.clear();    // clear string from OPCODE_BAD
-            pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
-        }
-        // otherwise, go to next token
-        else
-        {
-            ++pToken;
-        }
-    }
-}
-
-namespace {
-
-bool lclTokenHasChar( const ApiToken& rToken, sal_Int32 nOpCode, sal_Unicode cChar )
-{
-    return (rToken.OpCode == nOpCode) && rToken.Data.has< OUString >() && (rToken.Data.get< OUString >() == OUString( cChar ));
-}
-
-bool lclTokenHasDouble( const ApiToken& rToken, sal_Int32 nOpCode )
-{
-    return (rToken.OpCode == nOpCode) && rToken.Data.has< double >();
-}
-
-} // namespace
-
-const ApiToken* FormulaParserImpl::processParameters(
-        const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
+const FunctionInfo* FormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
 {
-    /*  OOXML import of library functions pushes the external reference "[n]!"
-        as BAD/PUSH/BAD/BAD tokens in front of the function name. Try to find
-        and remove them here. TODO: This will change with CWS mooxlsc, there,
-        the reference ID and function name are passed together in a BAD token,
-        see getFuncInfoFromLibFuncName(). */
-    if( (rFuncInfo.meFuncLibType != FUNCLIB_UNKNOWN) && (maTokenStorage.size() >= 5) )
+    /*  Try to parse calls to library functions. The format of such a function
+        call is "[n]!funcname", n>0 being the link identifier of the function
+        library spreadsheet file. */
+    sal_Int32 nBracketOpen = rTokenData.indexOf( '[' );
+    sal_Int32 nBracketClose = rTokenData.indexOf( ']' );
+    sal_Int32 nExclamation = rTokenData.indexOf( '!' );
+    if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < rTokenData.getLength()) )
     {
-        sal_Size nSize = maTokenStorage.size();
-        if( lclTokenHasChar(   maTokenStorage[ nSize - 5 ], OPCODE_BAD, '[' ) &&
-            lclTokenHasDouble( maTokenStorage[ nSize - 4 ], OPCODE_PUSH     ) &&
-            lclTokenHasChar(   maTokenStorage[ nSize - 3 ], OPCODE_BAD, ']' ) &&
-            lclTokenHasChar(   maTokenStorage[ nSize - 2 ], OPCODE_BAD, '!' ) )
+        sal_Int32 nRefId = rTokenData.copy( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ).toInt32();
+        const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
+        if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_LIBRARY) )
         {
-            maTokenStorage.erase( maTokenStorage.end() - 5, maTokenStorage.end() - 1 );
-        }
-    }
-
-    // remember position of the token containing the function op-code
-    size_t nFuncNameIdx = maTokenStorage.size() - 1;
-
-    // process a function, if an OPCODE_OPEN token is following
-    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaParserImpl::processParameters - OPCODE_OPEN expected" );
-    if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
-    {
-        // append the OPCODE_OPEN token to the vector
-        maTokenStorage.append( OPCODE_OPEN );
-
-        // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
-        ParameterPosVector aParams;
-        pToken = findParameters( aParams, pToken, pTokenEnd );
-        OSL_ENSURE( aParams.size() >= 2, "FormulaParserImpl::processParameters - missing tokens" );
-        size_t nParamCount = aParams.size() - 1;
-
-        if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
-        {
-            /*  Empty pair of parentheses -> function call without parameters,
-                process parameter, there might be spaces between parentheses. */
-            processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
-        }
-        else
-        {
-            const FunctionInfo* pRealFuncInfo = &rFuncInfo;
-            ParameterPosVector::const_iterator aPosIt = aParams.begin();
-
-            // preprocess add-ins, first parameter is reference to function name
-            if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
-            {
-                maTokenStorage[ nFuncNameIdx ].OpCode = OPCODE_NONAME;
-                // try to initialize function token from first parameter
-                if( const ApiToken* pECToken = getExternCallToken( *aPosIt + 1, *(aPosIt + 1) ) )
-                    if( const FunctionInfo* pECFuncInfo = convertExternCallParam( maTokenStorage[ nFuncNameIdx ], *pECToken ) )
-                        pRealFuncInfo = pECFuncInfo;
-                // on success, ignore first parameter
-                if( maTokenStorage[ nFuncNameIdx ].OpCode != OPCODE_NONAME )
-                {
-                    --nParamCount;
-                    ++aPosIt;
-                }
-            }
-
-            // process all parameters
-            FuncInfoParamClassIterator aClassIt( *pRealFuncInfo );
-            size_t nLastValidSize = maTokenStorage.size();
-            size_t nLastValidCount = 0;
-            for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aClassIt )
-            {
-                // add embedded Calc-only parameters
-                if( aClassIt.isCalcOnlyParam() )
-                {
-                    appendCalcOnlyParameter( *pRealFuncInfo, nParam );
-                    while( aClassIt.isCalcOnlyParam() ) ++aClassIt;
-                }
-
-                const ApiToken* pParamBegin = *aPosIt + 1;
-                const ApiToken* pParamEnd = *(aPosIt + 1);
-                bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
-
-                if( !aClassIt.isExcelOnlyParam() )
-                {
-                    // replace empty second and third parameter in IF function with zeros
-                    if( (pRealFuncInfo->mnOobFuncId == OOBIN_FUNC_IF) && ((nParam == 1) || (nParam == 2)) && bIsEmpty )
-                    {
-                        maTokenStorage.append< double >( OPCODE_PUSH, 0.0 );
-                        bIsEmpty = false;
-                    }
-                    else
-                    {
-                        // process all tokens of the parameter
-                        processTokens( pParamBegin, pParamEnd );
-                    }
-                    // append parameter separator token
-                    maTokenStorage.append( OPCODE_SEP );
-                }
-
-                /*  #84453# Update size of new token sequence with valid parameters
-                    to be able to remove trailing optional empty parameters. */
-                if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
-                {
-                    nLastValidSize = maTokenStorage.size();
-                    nLastValidCount = nParam + 1;
-                }
-            }
-
-            // #84453# remove trailing optional empty parameters
-            maTokenStorage.resize( nLastValidSize );
-
-            // add trailing Calc-only parameters
-            if( aClassIt.isCalcOnlyParam() )
-                appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
-
-            // add optional parameters that are required in Calc
-            appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
-
-            // remove last parameter separator token
-            if( maTokenStorage.back().OpCode == OPCODE_SEP )
-                maTokenStorage.pop_back();
-        }
-
-        /*  Append the OPCODE_CLOSE token to the vector, but only if there is
-            no OPCODE_BAD token at the end, this token already contains the
-            trailing closing parentheses. */
-        if( (pTokenEnd - 1)->OpCode != OPCODE_BAD )
-            maTokenStorage.append( OPCODE_CLOSE );
-    }
-
-    /*  Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
-        if no matching add-in function was found. */
-    ApiToken& rFuncNameToken = maTokenStorage[ nFuncNameIdx ];
-    if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
-        rFuncNameToken.OpCode = OPCODE_NONAME;
-
-    return pToken;
-}
-
-const FunctionInfo* FormulaParserImpl::getFuncInfoFromLibFuncName( const ApiToken& rToken ) const
-{
-    // try to parse calls to library functions
-    if( (rToken.OpCode == OPCODE_BAD) && rToken.Data.has< OUString >() )
-    {
-        // format of the function call is "[n]!funcname", n being the link to the library
-        OUString aString = rToken.Data.get< OUString >();
-        sal_Int32 nBracketOpen = aString.indexOf( '[' );
-        sal_Int32 nBracketClose = aString.indexOf( ']' );
-        sal_Int32 nExclamation = aString.indexOf( '!' );
-        if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < aString.getLength()) )
-        {
-            sal_Int32 nRefId = aString.copy( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ).toInt32();
-            const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
-            if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_LIBRARY) )
-                if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aString.copy( nExclamation + 1 ).toAsciiUpperCase() ) )
-                    if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
-                        return pFuncInfo;
-        }
-    }
-    return 0;
-}
-
-bool FormulaParserImpl::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
-{
-    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
-    if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
-    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
-    return pToken == pTokenEnd;
-}
-
-const ApiToken* FormulaParserImpl::getExternCallToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
-{
-    const ApiToken* pECToken = 0;
-    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
-    if( pToken < pTokenEnd ) pECToken = pToken++;
-    while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
-    return (pToken == pTokenEnd) ? pECToken : 0;
-}
-
-const FunctionInfo* FormulaParserImpl::convertExternCallParam( ApiToken& orFuncToken, const ApiToken& rECToken ) const
-{
-    if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
-    {
-        orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
-        // programmatic add-in function name
-        if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
-            orFuncToken.Data <<= pFuncInfo->maExtProgName;
-        // name of unsupported function, convert to OPCODE_BAD to preserve the name
-        else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && (pFuncInfo->maOoxFuncName.getLength() > 0) )
-            orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
-        return pFuncInfo;
-    }
-
-    if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
-    {
-        // macro call or unknown function name, move data to function token
-        orFuncToken = rECToken;
-    }
-    else if( rECToken.OpCode == OPCODE_NAME )
-    {
-        // defined name used as function call, convert to OPCODE_BAD to preserve the name
-        sal_Int32 nTokenIndex = 0;
-        if( rECToken.Data >>= nTokenIndex )
-        {
-            if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
-            {
-                orFuncToken.OpCode = OPCODE_BAD;
-                orFuncToken.Data <<= pDefName->getCalcName();
-            }
+            OUString aFuncName = rTokenData.copy( nExclamation + 1 ).toAsciiUpperCase();
+            if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName ) )
+                if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
+                    return pFuncInfo;
         }
     }
     return 0;
 }
 
-const ApiToken* FormulaParserImpl::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
+OUString FormulaParserImpl::resolveDefinedName( sal_Int32 nTokenIndex ) const
 {
-    // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
-    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
-    ++pToken;
-    while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
-    {
-        if( pToken->OpCode == OPCODE_OPEN )
-            pToken = skipParentheses( pToken, pTokenEnd );
-        else
-            ++pToken;
-    }
-    // skip the OPCODE_CLOSE token
-    OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
-    return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
-}
-
-const ApiToken* FormulaParserImpl::findParameters( ParameterPosVector& rParams,
-        const ApiToken* pToken, const ApiToken* pTokenEnd ) const
-{
-    // push position of OPCODE_OPEN
-    OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaParserImpl::findParameters - OPCODE_OPEN expected" );
-    rParams.push_back( pToken++ );
-
-    // find positions of parameter separators
-    while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
-    {
-        if( pToken->OpCode == OPCODE_OPEN )
-            pToken = skipParentheses( pToken, pTokenEnd );
-        else if( pToken->OpCode == OPCODE_SEP )
-            rParams.push_back( pToken++ );
-        else
-            ++pToken;
-    }
-
-    // push position of OPCODE_CLOSE
-    OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaParserImpl::findParameters - OPCODE_CLOSE expected" );
-    rParams.push_back( pToken );
-    return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
-}
-
-void FormulaParserImpl::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
-{
-    (void)nParam;   // prevent 'unused' warning
-    switch( rFuncInfo.mnOobFuncId )
-    {
-        case OOBIN_FUNC_FLOOR:
-        case OOBIN_FUNC_CEILING:
-            OSL_ENSURE( nParam == 2, "FormulaParserImpl::appendCalcOnlyParameter - unexpected parameter index" );
-            maTokenStorage.append< double >( OPCODE_PUSH, 1.0 );
-            maTokenStorage.append( OPCODE_SEP );
-        break;
-    }
-}
-
-void FormulaParserImpl::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
-{
-    switch( rFuncInfo.mnOobFuncId )
-    {
-        case OOBIN_FUNC_WEEKNUM:
-            if( nParamCount == 1 )
-            {
-                maTokenStorage.append< double >( OPCODE_PUSH, 1.0 );
-                maTokenStorage.append( OPCODE_SEP );
-            }
-        break;
-    }
-}
-
-void FormulaParserImpl::appendFinalToken( const ApiToken& rToken )
-{
-    if( (rToken.OpCode == OPCODE_MACRO) && !rToken.Data.hasValue() )
-    {
-        maTokenStorage.append( OPCODE_ARRAY_OPEN );
-        maTokenStorage.append( OPCODE_PUSH, BiffHelper::calcDoubleFromError( BIFF_ERR_NAME ) );
-        maTokenStorage.append( OPCODE_ARRAY_CLOSE );
-    }
-    else
-        maTokenStorage.push_back( rToken );
+    if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
+        return pDefName->getCalcName();
+    return OUString();
 }
 
 // OOX parser implementation ==================================================
@@ -1228,7 +1242,7 @@ void FormulaParserImpl::appendFinalToken( const ApiToken& rToken )
 class OoxFormulaParserImpl : public FormulaParserImpl
 {
 public:
-    explicit            OoxFormulaParserImpl( const OpCodeProvider& rOpCodeProv );
+    explicit            OoxFormulaParserImpl( const FormulaParser& rParent );
 
     virtual void        importOoxFormula(
                             FormulaContext& rContext,
@@ -1270,48 +1284,30 @@ private:
     bool                pushOobFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
 
 private:
-    Reference< XFormulaParser > mxParser;
-    PropertySet         maParserProps;
+    ApiParserWrapper    maApiParser;        /// Wrapper for the API formula parser object.
     sal_Int64           mnAddDataPos;       /// Current stream position for additional data (tExp, tArray, tMemArea).
     bool                mbNeedExtRefs;      /// True = parser needs initialization of external reference info.
 };
 
 // ----------------------------------------------------------------------------
 
-OoxFormulaParserImpl::OoxFormulaParserImpl( const OpCodeProvider& rOpCodeProv ) :
-    FormulaParserImpl( rOpCodeProv ),
+OoxFormulaParserImpl::OoxFormulaParserImpl( const FormulaParser& rParent ) :
+    FormulaParserImpl( rParent ),
+    maApiParser( rParent.getDocumentFactory(), rParent ),
     mnAddDataPos( 0 ),
     mbNeedExtRefs( true )
 {
-    try
-    {
-        mxParser.set( getDocumentFactory()->createInstance( CREATE_OUSTRING( "com.sun.star.sheet.FormulaParser" ) ), UNO_QUERY_THROW );
-    }
-    catch( Exception& )
-    {
-    }
-    OSL_ENSURE( mxParser.is(), "OoxFormulaParserImpl::OoxFormulaParserImpl - cannot create formula parser" );
-    maParserProps.set( mxParser );
-    maParserProps.setProperty( PROP_CompileEnglish, true );
-    maParserProps.setProperty( PROP_FormulaConvention, ::com::sun::star::sheet::AddressConvention::XL_OOX );
-    maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
-    maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
 }
 
-void OoxFormulaParserImpl::importOoxFormula(
-        FormulaContext& rContext, const OUString& rFormulaString )
+void OoxFormulaParserImpl::importOoxFormula( FormulaContext& rContext, const OUString& rFormulaString )
 {
-    if( mxParser.is() )
+    if( mbNeedExtRefs )
     {
-        if( mbNeedExtRefs )
-        {
-            maParserProps.setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
-            mbNeedExtRefs = false;
-        }
-        maParserProps.setProperty( PROP_ReferencePosition, rContext.getBaseAddress() );
-        initializeImport( rContext );
-        finalizeImport( mxParser->parseFormula( rFormulaString ) );
+        maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
+        mbNeedExtRefs = false;
     }
+    initializeImport( rContext );
+    finalizeImport( maApiParser.parseFormula( rFormulaString, rContext.getBaseAddress() ) );
 }
 
 void OoxFormulaParserImpl::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm )
@@ -1848,7 +1844,7 @@ bool lclIsValidNlrRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow
 class BiffFormulaParserImpl : public FormulaParserImpl
 {
 public:
-    explicit            BiffFormulaParserImpl( const OpCodeProvider& rOpCodeProv );
+    explicit            BiffFormulaParserImpl( const FormulaParser& rParent );
 
     virtual void        importBiffFormula(
                             FormulaContext& rContext,
@@ -1949,8 +1945,8 @@ private:
 
 // ----------------------------------------------------------------------------
 
-BiffFormulaParserImpl::BiffFormulaParserImpl( const OpCodeProvider& rOpCodeProv ) :
-    FormulaParserImpl( rOpCodeProv ),
+BiffFormulaParserImpl::BiffFormulaParserImpl( const FormulaParser& rParent ) :
+    FormulaParserImpl( rParent ),
     mnAddDataPos( 0 ),
     mnCurrRefId( 0 )
 {
diff --git a/oox/source/xls/makefile.mk b/oox/source/xls/makefile.mk
index 617b303..42a92ed 100644
--- a/oox/source/xls/makefile.mk
+++ b/oox/source/xls/makefile.mk
@@ -68,6 +68,7 @@ SLOFILES =										\
         $(SLO)$/formulabase.obj					\
         $(SLO)$/formulaparser.obj				\
         $(SLO)$/numberformatsbuffer.obj			\
+        $(SLO)$/ooxformulaparser.obj			\
         $(SLO)$/pagesettings.obj				\
         $(SLO)$/pivotcachebuffer.obj			\
         $(SLO)$/pivotcachefragment.obj			\
diff --git a/oox/source/xls/ooxformulaparser.cxx b/oox/source/xls/ooxformulaparser.cxx
new file mode 100644
index 0000000..62e8189
--- /dev/null
+++ b/oox/source/xls/ooxformulaparser.cxx
@@ -0,0 +1,228 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: ooxformulaparser.cxx,v $
+ * $Revision: 1.1 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#include "oox/xls/ooxformulaparser.hxx"
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include "oox/xls/formulaparser.hxx"
+
+using ::rtl::OUString;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::XComponentContext;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::sheet::FormulaToken;
+
+namespace oox {
+namespace xls {
+
+// ============================================================================
+
+class OOXMLFormulaParserImpl : private FormulaFinalizer
+{
+public:
+    explicit            OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxFactory );
+
+    Sequence< FormulaToken > parseFormula( const OUString& rFormula, const CellAddress& rReferencePos );
+
+protected:
+    virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
+
+private:
+    ApiParserWrapper    maApiParser;
+};
+
+// ----------------------------------------------------------------------------
+
+OOXMLFormulaParserImpl::OOXMLFormulaParserImpl( const Reference< XMultiServiceFactory >& rxFactory ) :
+    FormulaFinalizer( OpCodeProvider( rxFactory, FILTER_OOX, BIFF_UNKNOWN, true ) ),
+    maApiParser( rxFactory, *this )
+{
+}
+
+Sequence< FormulaToken > OOXMLFormulaParserImpl::parseFormula( const OUString& rFormula, const CellAddress& rReferencePos )
+{
+    return finalizeTokenArray( maApiParser.parseFormula( rFormula, rReferencePos ) );
+}
+
+const FunctionInfo* OOXMLFormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
+{
+    /*  Try to parse calls to library functions. The format of such a function
+        call is assumed to be
+            "'<path-to-office-install>\Library\<libname>'!<funcname>". */
+
+    // the string has to start with an apostroph (followed by the library URL)
+    if( (rTokenData.getLength() >= 6) && (rTokenData[ 0 ] == '\'') )
+    {
+        // library URL and function name are separated by an exclamation mark
+        sal_Int32 nExclamPos = rTokenData.lastIndexOf( '!' );
+        if( (1 < nExclamPos) && (nExclamPos + 1 < rTokenData.getLength()) && (rTokenData[ nExclamPos - 1 ] == '\'') )
+        {
+            // find the last backslash that separates library path and name
+            sal_Int32 nFileSep = rTokenData.lastIndexOf( '\\', nExclamPos - 2 );
+            if( nFileSep > 1 )
+            {
+                // find preceding backslash that separates the last directory name
+                sal_Int32 nDirSep = rTokenData.lastIndexOf( '\\', nFileSep - 1 );
+                // function library is located in a directory called 'library'
+                if( (nDirSep > 0) && rTokenData.matchIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "\\LIBRARY\\" ), nDirSep ) )
+                {
+                    // try to find a function info for the function name
+                    OUString aFuncName = rTokenData.copy( nExclamPos + 1 ).toAsciiUpperCase();
+                    const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName );
+                    if( pFuncInfo && (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) )
+                    {
+                        // check that the name of the library matches
+                        OUString aLibName = rTokenData.copy( nFileSep + 1, nExclamPos - nFileSep - 2 );
+                        if( pFuncInfo->meFuncLibType == getFuncLibTypeFromLibraryName( aLibName ) )
+                            return pFuncInfo;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+// ============================================================================
+
+class OOXMLFormulaPrinterImpl : public OpCodeProvider
+{
+public:
+    explicit            OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxFactory );
+
+private:
+    ApiParserWrapper    maApiParser;
+};
+
+// ----------------------------------------------------------------------------
+
+OOXMLFormulaPrinterImpl::OOXMLFormulaPrinterImpl( const Reference< XMultiServiceFactory >& rxFactory ) :
+    OpCodeProvider( rxFactory, FILTER_OOX, BIFF_UNKNOWN, false ),
+    maApiParser( rxFactory, *this )
+{
+}
+
+// ============================================================================
+
+Sequence< OUString > OOXMLFormulaParser_getSupportedServiceNames()
+{
+    Sequence< OUString > aServiceNames( 1 );
+    aServiceNames[ 0 ] = CREATE_OUSTRING( "com.sun.star.sheet.FilterFormulaParser" );
+    return aServiceNames;
+}
+
+OUString OOXMLFormulaParser_getImplementationName()
+{
+    return CREATE_OUSTRING( "com.sun.star.comp.oox.OOXMLFormulaParser" );
+}
+
+Reference< XInterface > SAL_CALL OOXMLFormulaParser_createInstance( const Reference< XComponentContext >& ) throw( Exception )
+{
+    return static_cast< ::cppu::OWeakObject* >( new OOXMLFormulaParser );
+}
+
+// ============================================================================
+
+OOXMLFormulaParser::OOXMLFormulaParser()
+{
+}
+
+OOXMLFormulaParser::~OOXMLFormulaParser()
+{
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL OOXMLFormulaParser::getImplementationName() throw( RuntimeException )
+{
+    return OOXMLFormulaParser_getImplementationName();
+}
+
+sal_Bool SAL_CALL OOXMLFormulaParser::supportsService( const OUString& rService ) throw( RuntimeException )
+{
+    const Sequence< OUString > aServices( OOXMLFormulaParser_getSupportedServiceNames() );
+    const OUString* pArray = aServices.getConstArray();
+    const OUString* pArrayEnd = pArray + aServices.getLength();
+    return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
+}
+
+Sequence< OUString > SAL_CALL OOXMLFormulaParser::getSupportedServiceNames() throw( RuntimeException )
+{
+    return OOXMLFormulaParser_getSupportedServiceNames();
+}
+
+// com.sun.star.lang.XInitialization interface --------------------------------
+
+void SAL_CALL OOXMLFormulaParser::initialize( const Sequence< Any >& rArgs ) throw( Exception, RuntimeException )
+{
+    OSL_ENSURE( rArgs.hasElements(), "OOXMLFormulaParser::initialize - missing arguments" );
+    if( !rArgs.hasElements() )
+        throw RuntimeException();
+    mxComponent.set( rArgs[ 0 ], UNO_QUERY_THROW );
+}
+
+// com.sun.star.sheet.XFilterFormulaParser interface --------------------------
+
+OUString SAL_CALL OOXMLFormulaParser::getSupportedNamespace() throw( RuntimeException )
+{
+    return CREATE_OUSTRING( "http://schemas.microsoft.com/office/excel/formula" );
+}
+
+// com.sun.star.sheet.XFormulaParser interface --------------------------------
+
+Sequence< FormulaToken > SAL_CALL OOXMLFormulaParser::parseFormula(
+        const OUString& rFormula, const CellAddress& rReferencePos ) throw( RuntimeException )
+{
+    if( !mxParserImpl )
+    {
+        Reference< XMultiServiceFactory > xFactory( mxComponent, UNO_QUERY_THROW );
+        mxParserImpl.reset( new OOXMLFormulaParserImpl( xFactory ) );
+    }
+    return mxParserImpl->parseFormula( rFormula, rReferencePos );
+}
+
+OUString SAL_CALL OOXMLFormulaParser::printFormula(
+        const Sequence< FormulaToken >& /*rTokens*/, const CellAddress& /*rReferencePos*/ ) throw( RuntimeException )
+{
+    // not implemented
+    throw RuntimeException();
+}
+
+// ============================================================================
+
+} // namespace xls
+} // namespace oox
+


More information about the ooo-build-commit mailing list