[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