LCOV - code coverage report
Current view: top level - sc/source/filter/oox - formulabase.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 322 524 61.5 %
Date: 2014-11-03 Functions: 40 71 56.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "formulabase.hxx"
      21             : 
      22             : #include <map>
      23             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      24             : #include <com/sun/star/table/XCellRange.hpp>
      25             : #include <com/sun/star/sheet/AddressConvention.hpp>
      26             : #include <com/sun/star/sheet/ReferenceFlags.hpp>
      27             : #include <com/sun/star/sheet/SingleReference.hpp>
      28             : #include <com/sun/star/sheet/ComplexReference.hpp>
      29             : #include <com/sun/star/sheet/FormulaLanguage.hpp>
      30             : #include <com/sun/star/sheet/FormulaMapGroup.hpp>
      31             : #include <com/sun/star/sheet/FormulaMapGroupSpecialOffset.hpp>
      32             : #include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
      33             : #include <com/sun/star/sheet/XFormulaParser.hpp>
      34             : #include <rtl/strbuf.hxx>
      35             : #include <rtl/ustrbuf.hxx>
      36             : #include <sal/log.hxx>
      37             : #include <oox/core/filterbase.hxx>
      38             : #include <oox/helper/containerhelper.hxx>
      39             : #include <oox/token/properties.hxx>
      40             : #include "biffinputstream.hxx"
      41             : 
      42             : namespace oox {
      43             : namespace xls {
      44             : 
      45             : using namespace ::com::sun::star::lang;
      46             : using namespace ::com::sun::star::sheet;
      47             : using namespace ::com::sun::star::table;
      48             : using namespace ::com::sun::star::uno;
      49             : 
      50             : // reference helpers ==========================================================
      51             : 
      52           0 : BinSingleRef2d::BinSingleRef2d() :
      53             :     mnCol( 0 ),
      54             :     mnRow( 0 ),
      55             :     mbColRel( false ),
      56           0 :     mbRowRel( false )
      57             : {
      58           0 : }
      59             : 
      60           0 : void BinSingleRef2d::setBiff12Data( sal_uInt16 nCol, sal_Int32 nRow, bool bRelativeAsOffset )
      61             : {
      62           0 :     mnCol = nCol & BIFF12_TOK_REF_COLMASK;
      63           0 :     mnRow = nRow & BIFF12_TOK_REF_ROWMASK;
      64           0 :     mbColRel = getFlag( nCol, BIFF12_TOK_REF_COLREL );
      65           0 :     mbRowRel = getFlag( nCol, BIFF12_TOK_REF_ROWREL );
      66           0 :     if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF12_TOK_REF_COLMASK >> 1)) )
      67           0 :         mnCol -= (BIFF12_TOK_REF_COLMASK + 1);
      68           0 :     if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF12_TOK_REF_ROWMASK >> 1)) )
      69           0 :         mnRow -= (BIFF12_TOK_REF_ROWMASK + 1);
      70           0 : }
      71             : 
      72           0 : void BinSingleRef2d::setBiff2Data( sal_uInt8 nCol, sal_uInt16 nRow, bool bRelativeAsOffset )
      73             : {
      74           0 :     mnCol = nCol;
      75           0 :     mnRow = nRow & BIFF_TOK_REF_ROWMASK;
      76           0 :     mbColRel = getFlag( nRow, BIFF_TOK_REF_COLREL );
      77           0 :     mbRowRel = getFlag( nRow, BIFF_TOK_REF_ROWREL );
      78           0 :     if( bRelativeAsOffset && mbColRel && (mnCol >= 0x80) )
      79           0 :         mnCol -= 0x100;
      80           0 :     if( bRelativeAsOffset && mbRowRel && (mnRow > (BIFF_TOK_REF_ROWMASK >> 1)) )
      81           0 :         mnRow -= (BIFF_TOK_REF_ROWMASK + 1);
      82           0 : }
      83             : 
      84           0 : void BinSingleRef2d::setBiff8Data( sal_uInt16 nCol, sal_uInt16 nRow, bool bRelativeAsOffset )
      85             : {
      86           0 :     mnCol = nCol & BIFF_TOK_REF_COLMASK;
      87           0 :     mnRow = nRow;
      88           0 :     mbColRel = getFlag( nCol, BIFF_TOK_REF_COLREL );
      89           0 :     mbRowRel = getFlag( nCol, BIFF_TOK_REF_ROWREL );
      90           0 :     if( bRelativeAsOffset && mbColRel && (mnCol > (BIFF_TOK_REF_COLMASK >> 1)) )
      91           0 :         mnCol -= (BIFF_TOK_REF_COLMASK + 1);
      92           0 :     if( bRelativeAsOffset && mbRowRel && (mnRow >= 0x8000) )
      93           0 :         mnRow -= 0x10000;
      94           0 : }
      95             : 
      96           0 : void BinSingleRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
      97             : {
      98             :     sal_Int32 nRow;
      99             :     sal_uInt16 nCol;
     100           0 :     rStrm >> nRow >> nCol;
     101           0 :     setBiff12Data( nCol, nRow, bRelativeAsOffset );
     102           0 : }
     103             : 
     104           0 : void BinSingleRef2d::readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
     105             : {
     106             :     sal_uInt16 nRow;
     107             :     sal_uInt8 nCol;
     108           0 :     rStrm >> nRow >> nCol;
     109           0 :     setBiff2Data( nCol, nRow, bRelativeAsOffset );
     110           0 : }
     111             : 
     112           0 : void BinSingleRef2d::readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
     113             : {
     114             :     sal_uInt16 nRow, nCol;
     115           0 :     rStrm >> nRow >> nCol;
     116           0 :     setBiff8Data( nCol, nRow, bRelativeAsOffset );
     117           0 : }
     118             : 
     119           0 : void BinComplexRef2d::readBiff12Data( SequenceInputStream& rStrm, bool bRelativeAsOffset )
     120             : {
     121             :     sal_Int32 nRow1, nRow2;
     122             :     sal_uInt16 nCol1, nCol2;
     123           0 :     rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
     124           0 :     maRef1.setBiff12Data( nCol1, nRow1, bRelativeAsOffset );
     125           0 :     maRef2.setBiff12Data( nCol2, nRow2, bRelativeAsOffset );
     126           0 : }
     127             : 
     128           0 : void BinComplexRef2d::readBiff2Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
     129             : {
     130             :     sal_uInt16 nRow1, nRow2;
     131             :     sal_uInt8 nCol1, nCol2;
     132           0 :     rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
     133           0 :     maRef1.setBiff2Data( nCol1, nRow1, bRelativeAsOffset );
     134           0 :     maRef2.setBiff2Data( nCol2, nRow2, bRelativeAsOffset );
     135           0 : }
     136             : 
     137           0 : void BinComplexRef2d::readBiff8Data( BiffInputStream& rStrm, bool bRelativeAsOffset )
     138             : {
     139             :     sal_uInt16 nRow1, nRow2, nCol1, nCol2;
     140           0 :     rStrm >> nRow1 >> nRow2 >> nCol1 >> nCol2;
     141           0 :     maRef1.setBiff8Data( nCol1, nRow1, bRelativeAsOffset );
     142           0 :     maRef2.setBiff8Data( nCol2, nRow2, bRelativeAsOffset );
     143           0 : }
     144             : 
     145             : // token vector, sequence =====================================================
     146             : 
     147         776 : ApiTokenVector::ApiTokenVector()
     148         776 :     : mvTokens()
     149             : {
     150         776 : }
     151             : 
     152           0 : Any& ApiTokenVector::append( sal_Int32 nOpCode )
     153             : {
     154           0 :     mvTokens.resize( mvTokens.size() + 1 );
     155           0 :     mvTokens.back().OpCode = nOpCode;
     156           0 :     return mvTokens.back().Data;
     157             : }
     158             : 
     159         148 : ApiTokenSequence ApiTokenVector::toSequence() const
     160             : {
     161         148 :     return ContainerHelper::vectorToSequence( mvTokens );
     162             : }
     163             : 
     164             : // token sequence iterator ====================================================
     165             : 
     166           2 : ApiTokenIterator::ApiTokenIterator( const ApiTokenSequence& rTokens, sal_Int32 nSpacesOpCode, bool bSkipSpaces ) :
     167           2 :     mpToken( rTokens.getConstArray() ),
     168           2 :     mpTokenEnd( rTokens.getConstArray() + rTokens.getLength() ),
     169             :     mnSpacesOpCode( nSpacesOpCode ),
     170           4 :     mbSkipSpaces( bSkipSpaces )
     171             : {
     172           2 :     skipSpaces();
     173           2 : }
     174             : 
     175           2 : ApiTokenIterator& ApiTokenIterator::operator++()
     176             : {
     177           2 :     if( is() )
     178             :     {
     179           2 :         ++mpToken;
     180           2 :         skipSpaces();
     181             :     }
     182           2 :     return *this;
     183             : }
     184             : 
     185           4 : void ApiTokenIterator::skipSpaces()
     186             : {
     187           4 :     if( mbSkipSpaces )
     188           8 :         while( is() && (mpToken->OpCode == mnSpacesOpCode) )
     189           0 :             ++mpToken;
     190           4 : }
     191             : 
     192             : // function data ==============================================================
     193             : 
     194             : namespace {
     195             : 
     196             : const size_t FUNCINFO_PARAMINFOCOUNT        = 5;        /// Number of parameter type entries.
     197             : 
     198             : const sal_uInt16 FUNCFLAG_VOLATILE          = 0x0001;   /// Result is volatile (e.g. NOW() function).
     199             : const sal_uInt16 FUNCFLAG_IMPORTONLY        = 0x0002;   /// Only used in import filter.
     200             : const sal_uInt16 FUNCFLAG_EXPORTONLY        = 0x0004;   /// Only used in export filter.
     201             : const sal_uInt16 FUNCFLAG_MACROCALL         = 0x0008;   /// Function is stored as macro call in BIFF Excel (_xlfn. prefix). OOXML name MUST exist.
     202             : const sal_uInt16 FUNCFLAG_MACROCALLODF      = 0x0010;   /// ODF-only function stored as macro call in BIFF Excel (_xlfnodf. prefix). ODF name MUST exist.
     203             : const sal_uInt16 FUNCFLAG_EXTERNAL          = 0x0020;   /// Function is external in Calc.
     204             : const sal_uInt16 FUNCFLAG_MACROFUNC         = 0x0040;   /// Function is a macro-sheet function.
     205             : const sal_uInt16 FUNCFLAG_MACROCMD          = 0x0080;   /// Function is a macro-sheet command.
     206             : const sal_uInt16 FUNCFLAG_ALWAYSVAR         = 0x0100;   /// Function is always represented by a tFuncVar token.
     207             : const sal_uInt16 FUNCFLAG_PARAMPAIRS        = 0x0200;   /// Optional parameters are expected to appear in pairs.
     208             : const sal_uInt16 FUNCFLAG_MACROCALL_FN      = 0x0400;   /** Function is stored as macro call in Excel (_xlfn. prefix)
     209             :                                                             for OOXML. OOXML name MUST exist. Do not use without
     210             :                                                             FUNCFLAG_MACROCALL. */
     211             : const sal_uInt16 FUNCFLAG_MACROCALL_NEW     = FUNCFLAG_MACROCALL | FUNCFLAG_MACROCALL_FN;   /** New Excel functions not
     212             :                                                             defined in OOXML, _xlfn. prefix in all formats. OOXML name
     213             :                                                             must exist. */
     214             : const sal_uInt16 FUNCFLAG_BIFFIMPORTONLY    = 0x0800;   /// Only used in BIFF binary import filter.
     215             : const sal_uInt16 FUNCFLAG_BIFFEXPORTONLY    = 0x1000;   /// Only used in BIFF binary export filter.
     216             : const sal_uInt16 FUNCFLAG_INTERNAL          = 0x2000;   /// Function is internal in Calc.
     217             : 
     218             : /// Converts a function library index (value of enum FunctionLibraryType) to function flags.
     219             : #define FUNCLIB_TO_FUNCFLAGS( funclib_index ) static_cast< sal_uInt16 >( static_cast< sal_uInt8 >( funclib_index ) << 12 )
     220             : /// Extracts a function library index (value of enum FunctionLibraryType) from function flags.
     221             : #define FUNCFLAGS_TO_FUNCLIB( func_flags ) extractValue< FunctionLibraryType >( func_flags, 12, 4 )
     222             : 
     223             : typedef ::boost::shared_ptr< FunctionInfo > FunctionInfoRef;
     224             : 
     225             : struct FunctionData
     226             : {
     227             :     const sal_Char*     mpcOdfFuncName;     /// ODF function name.
     228             :     const sal_Char*     mpcOoxFuncName;     /// OOXML function name.
     229             :     sal_uInt16          mnBiff12FuncId;     /// BIFF12 function identifier.
     230             :     sal_uInt16          mnBiffFuncId;       /// BIFF2-BIFF8 function identifier.
     231             :     sal_uInt8           mnMinParamCount;    /// Minimum number of parameters.
     232             :     sal_uInt8           mnMaxParamCount;    /// Maximum number of parameters.
     233             :     sal_uInt8           mnRetClass;         /// BIFF token class of the return value.
     234             :     FunctionParamInfo   mpParamInfos[ FUNCINFO_PARAMINFOCOUNT ]; /// Information about all parameters.
     235             :     sal_uInt16          mnFlags;            /// Additional flags.
     236             : 
     237             :     inline bool         isSupported( bool bImportFilter, FilterType eFilter ) const;
     238             : };
     239             : 
     240      229614 : inline bool FunctionData::isSupported( bool bImportFilter, FilterType eFilter ) const
     241             : {
     242             :     /*  For import filters: the FUNCFLAG_EXPORTONLY and FUNCFLAG_BIFFEXPORTONLY flag must not be set.
     243             :         For OOXML import:   the FUNCFLAG_BIFFIMPORTONLY flag must not be set.
     244             :         For export filters: the FUNCFLAG_IMPORTONLY and FUNCFLAG_BIFFIMPORTONLY flag must not be set.
     245             :         For OOXML export:   the FUNCFLAG_BIFFEXPORTONLY flag must not be set. */
     246             :     bool bSupported = !getFlag( mnFlags, static_cast<sal_uInt16>(bImportFilter ?
     247             :                 (FUNCFLAG_EXPORTONLY | FUNCFLAG_BIFFEXPORTONLY) :
     248      229614 :                 (FUNCFLAG_IMPORTONLY | FUNCFLAG_BIFFIMPORTONLY)));
     249      229614 :     if (bSupported && eFilter == FILTER_OOXML)
     250      225202 :         bSupported = !getFlag( mnFlags, bImportFilter ? FUNCFLAG_BIFFIMPORTONLY : FUNCFLAG_BIFFEXPORTONLY );
     251      229614 :     return bSupported;
     252             : }
     253             : 
     254             : const sal_uInt16 NOID = SAL_MAX_UINT16;     /// No BIFF function identifier available.
     255             : const sal_uInt8 MX    = SAL_MAX_UINT8;      /// Maximum parameter count.
     256             : 
     257             : // abbreviations for function return token class
     258             : const sal_uInt8 R = BIFF_TOKCLASS_REF;
     259             : const sal_uInt8 V = BIFF_TOKCLASS_VAL;
     260             : const sal_uInt8 A = BIFF_TOKCLASS_ARR;
     261             : 
     262             : // abbreviations for parameter infos
     263             : #define RO   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_ORG, false }
     264             : #define RA   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_ARR, false }
     265             : #define RR   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_RPT, false }
     266             : #define RX   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_RPX, false }
     267             : #define VO   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_ORG, true  }
     268             : #define VV   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_VAL, true  }
     269             : #define VA   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_ARR, true  }
     270             : #define VR   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_RPT, true  }
     271             : #define VX   { FUNC_PARAM_REGULAR,   FUNC_PARAMCONV_RPX, true  }
     272             : #define RO_E { FUNC_PARAM_EXCELONLY, FUNC_PARAMCONV_ORG, false }
     273             : #define VR_E { FUNC_PARAM_EXCELONLY, FUNC_PARAMCONV_RPT, true  }
     274             : #define C    { FUNC_PARAM_CALCONLY,  FUNC_PARAMCONV_ORG, false }
     275             : 
     276             : // Note: parameter types of all macro sheet functions (FUNCFLAG_MACROFUNC/FUNCFLAG_MACROCMD) untested!
     277             : 
     278             : /** Functions new in BIFF2. */
     279             : static const FunctionData saFuncTableBiff2[] =
     280             : {
     281             :     { "COUNT",                  "COUNT",                0,      0,      0,  MX, V, { RX }, 0 },
     282             :     { "IF",                     "IF",                   1,      1,      2,  3,  R, { VO, RO }, 0 },
     283             :     { "ISNA",                   "ISNA",                 2,      2,      1,  1,  V, { VR }, 0 },
     284             :     { "ISERROR",                "ISERROR",              3,      3,      1,  1,  V, { VR }, 0 },
     285             :     { "SUM",                    "SUM",                  4,      4,      0,  MX, V, { RX }, 0 },
     286             :     { "AVERAGE",                "AVERAGE",              5,      5,      1,  MX, V, { RX }, 0 },
     287             :     { "MIN",                    "MIN",                  6,      6,      1,  MX, V, { RX }, 0 },
     288             :     { "MAX",                    "MAX",                  7,      7,      1,  MX, V, { RX }, 0 },
     289             :     { "ROW",                    "ROW",                  8,      8,      0,  1,  V, { RO }, 0 },
     290             :     { "COLUMN",                 "COLUMN",               9,      9,      0,  1,  V, { RO }, 0 },
     291             :     { "NA",                     "NA",                   10,     10,     0,  0,  V, {}, 0 },
     292             :     { "NPV",                    "NPV",                  11,     11,     2,  MX, V, { VR, RX }, 0 },
     293             :     { "STDEV",                  "STDEV",                12,     12,     1,  MX, V, { RX }, 0 },
     294             :     { "DOLLAR",                 "DOLLAR",               13,     13,     1,  2,  V, { VR }, 0 },
     295             :     { "FIXED",                  "FIXED",                14,     14,     1,  2,  V, { VR, VR, C }, 0 },
     296             :     { "SIN",                    "SIN",                  15,     15,     1,  1,  V, { VR }, 0 },
     297             :     { "CSC",                    "SIN",                  15,     15,     1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     298             :     { "COS",                    "COS",                  16,     16,     1,  1,  V, { VR }, 0 },
     299             :     { "SEC",                    "COS",                  16,     16,     1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     300             :     { "TAN",                    "TAN",                  17,     17,     1,  1,  V, { VR }, 0 },
     301             :     { "COT",                    "TAN",                  17,     17,     1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     302             :     { "ATAN",                   "ATAN",                 18,     18,     1,  1,  V, { VR }, 0 },
     303             :     { "ACOT",                   "ATAN",                 18,     18,     1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     304             :     { "PI",                     "PI",                   19,     19,     0,  0,  V, {}, 0 },
     305             :     { "SQRT",                   "SQRT",                 20,     20,     1,  1,  V, { VR }, 0 },
     306             :     { "EXP",                    "EXP",                  21,     21,     1,  1,  V, { VR }, 0 },
     307             :     { "LN",                     "LN",                   22,     22,     1,  1,  V, { VR }, 0 },
     308             :     { "LOG10",                  "LOG10",                23,     23,     1,  1,  V, { VR }, 0 },
     309             :     { "ABS",                    "ABS",                  24,     24,     1,  1,  V, { VR }, 0 },
     310             :     { "INT",                    "INT",                  25,     25,     1,  1,  V, { VR }, 0 },
     311             :     { "SIGN",                   "SIGN",                 26,     26,     1,  1,  V, { VR }, 0 },
     312             :     { "ROUND",                  "ROUND",                27,     27,     2,  2,  V, { VR }, 0 },
     313             :     { "LOOKUP",                 "LOOKUP",               28,     28,     2,  3,  V, { VR, RA }, 0 },
     314             :     { "INDEX",                  "INDEX",                29,     29,     2,  4,  R, { RA, VV }, 0 },
     315             :     { "REPT",                   "REPT",                 30,     30,     2,  2,  V, { VR }, 0 },
     316             :     { "MID",                    "MID",                  31,     31,     3,  3,  V, { VR }, 0 },
     317             :     { "LEN",                    "LEN",                  32,     32,     1,  1,  V, { VR }, 0 },
     318             :     { "VALUE",                  "VALUE",                33,     33,     1,  1,  V, { VR }, 0 },
     319             :     { "TRUE",                   "TRUE",                 34,     34,     0,  0,  V, {}, 0 },
     320             :     { "FALSE",                  "FALSE",                35,     35,     0,  0,  V, {}, 0 },
     321             :     { "AND",                    "AND",                  36,     36,     1,  MX, V, { RX }, 0 },
     322             :     { "OR",                     "OR",                   37,     37,     1,  MX, V, { RX }, 0 },
     323             :     { "NOT",                    "NOT",                  38,     38,     1,  1,  V, { VR }, 0 },
     324             :     { "MOD",                    "MOD",                  39,     39,     2,  2,  V, { VR }, 0 },
     325             :     { "DCOUNT",                 "DCOUNT",               40,     40,     3,  3,  V, { RO, RR }, 0 },
     326             :     { "DSUM",                   "DSUM",                 41,     41,     3,  3,  V, { RO, RR }, 0 },
     327             :     { "DAVERAGE",               "DAVERAGE",             42,     42,     3,  3,  V, { RO, RR }, 0 },
     328             :     { "DMIN",                   "DMIN",                 43,     43,     3,  3,  V, { RO, RR }, 0 },
     329             :     { "DMAX",                   "DMAX",                 44,     44,     3,  3,  V, { RO, RR }, 0 },
     330             :     { "DSTDEV",                 "DSTDEV",               45,     45,     3,  3,  V, { RO, RR }, 0 },
     331             :     { "VAR",                    "VAR",                  46,     46,     1,  MX, V, { RX }, 0 },
     332             :     { "DVAR",                   "DVAR",                 47,     47,     3,  3,  V, { RO, RR }, 0 },
     333             :     { "TEXT",                   "TEXT",                 48,     48,     2,  2,  V, { VR }, 0 },
     334             :     { "LINEST",                 "LINEST",               49,     49,     1,  2,  A, { RA, RA, C, C }, 0 },
     335             :     { "TREND",                  "TREND",                50,     50,     1,  3,  A, { RA, RA, RA, C }, 0 },
     336             :     { "LOGEST",                 "LOGEST",               51,     51,     1,  2,  A, { RA, RA, C, C }, 0 },
     337             :     { "GROWTH",                 "GROWTH",               52,     52,     1,  3,  A, { RA, RA, RA, C }, 0 },
     338             :     { "PV",                     "PV",                   56,     56,     3,  5,  V, { VR }, 0 },
     339             :     { "FV",                     "FV",                   57,     57,     3,  5,  V, { VR }, 0 },
     340             :     { "NPER",                   "NPER",                 58,     58,     3,  5,  V, { VR }, 0 },
     341             :     { "PMT",                    "PMT",                  59,     59,     3,  5,  V, { VR }, 0 },
     342             :     { "RATE",                   "RATE",                 60,     60,     3,  6,  V, { VR }, 0 },
     343             :     { "MIRR",                   "MIRR",                 61,     61,     3,  3,  V, { RA, VR }, 0 },
     344             :     { "IRR",                    "IRR",                  62,     62,     1,  2,  V, { RA, VR }, 0 },
     345             :     { "RAND",                   "RAND",                 63,     63,     0,  0,  V, {}, FUNCFLAG_VOLATILE },
     346             :     { "MATCH",                  "MATCH",                64,     64,     2,  3,  V, { VR, RX, RR }, 0 },
     347             :     { "DATE",                   "DATE",                 65,     65,     3,  3,  V, { VR }, 0 },
     348             :     { "TIME",                   "TIME",                 66,     66,     3,  3,  V, { VR }, 0 },
     349             :     { "DAY",                    "DAY",                  67,     67,     1,  1,  V, { VR }, 0 },
     350             :     { "MONTH",                  "MONTH",                68,     68,     1,  1,  V, { VR }, 0 },
     351             :     { "YEAR",                   "YEAR",                 69,     69,     1,  1,  V, { VR }, 0 },
     352             :     { "WEEKDAY",                "WEEKDAY",              70,     70,     1,  1,  V, { VR, C }, 0 },
     353             :     { "HOUR",                   "HOUR",                 71,     71,     1,  1,  V, { VR }, 0 },
     354             :     { "MINUTE",                 "MINUTE",               72,     72,     1,  1,  V, { VR }, 0 },
     355             :     { "SECOND",                 "SECOND",               73,     73,     1,  1,  V, { VR }, 0 },
     356             :     { "NOW",                    "NOW",                  74,     74,     0,  0,  V, {}, FUNCFLAG_VOLATILE },
     357             :     { "AREAS",                  "AREAS",                75,     75,     1,  1,  V, { RO }, 0 },
     358             :     { "ROWS",                   "ROWS",                 76,     76,     1,  1,  V, { RO }, 0 },
     359             :     { "COLUMNS",                "COLUMNS",              77,     77,     1,  1,  V, { RO }, 0 },
     360             :     { "OFFSET",                 "OFFSET",               78,     78,     3,  5,  R, { RO, VR }, FUNCFLAG_VOLATILE },
     361             :     { "SEARCH",                 "SEARCH",               82,     82,     2,  3,  V, { VR }, 0 },
     362             :     { "TRANSPOSE",              "TRANSPOSE",            83,     83,     1,  1,  A, { VO }, 0 },
     363             :     { "TYPE",                   "TYPE",                 86,     86,     1,  1,  V, { VX }, 0 },
     364             :     { "ATAN2",                  "ATAN2",                97,     97,     2,  2,  V, { VR }, 0 },
     365             :     { "ASIN",                   "ASIN",                 98,     98,     1,  1,  V, { VR }, 0 },
     366             :     { "ACOS",                   "ACOS",                 99,     99,     1,  1,  V, { VR }, 0 },
     367             :     { "CHOOSE",                 "CHOOSE",               100,    100,    2,  MX, R, { VO, RO }, 0 },
     368             :     { "HLOOKUP",                "HLOOKUP",              101,    101,    3,  3,  V, { VV, RO, RO, C }, 0 },
     369             :     { "VLOOKUP",                "VLOOKUP",              102,    102,    3,  3,  V, { VV, RO, RO, C }, 0 },
     370             :     { "ISREF",                  "ISREF",                105,    105,    1,  1,  V, { RX }, 0 },
     371             :     { "LOG",                    "LOG",                  109,    109,    1,  2,  V, { VR }, 0 },
     372             :     { "CHAR",                   "CHAR",                 111,    111,    1,  1,  V, { VR }, 0 },
     373             :     { "LOWER",                  "LOWER",                112,    112,    1,  1,  V, { VR }, 0 },
     374             :     { "UPPER",                  "UPPER",                113,    113,    1,  1,  V, { VR }, 0 },
     375             :     { "PROPER",                 "PROPER",               114,    114,    1,  1,  V, { VR }, 0 },
     376             :     { "LEFT",                   "LEFT",                 115,    115,    1,  2,  V, { VR }, 0 },
     377             :     { "RIGHT",                  "RIGHT",                116,    116,    1,  2,  V, { VR }, 0 },
     378             :     { "EXACT",                  "EXACT",                117,    117,    2,  2,  V, { VR }, 0 },
     379             :     { "TRIM",                   "TRIM",                 118,    118,    1,  1,  V, { VR }, 0 },
     380             :     { "REPLACE",                "REPLACE",              119,    119,    4,  4,  V, { VR }, 0 },
     381             :     { "SUBSTITUTE",             "SUBSTITUTE",           120,    120,    3,  4,  V, { VR }, 0 },
     382             :     { "CODE",                   "CODE",                 121,    121,    1,  1,  V, { VR }, 0 },
     383             :     { "FIND",                   "FIND",                 124,    124,    2,  3,  V, { VR }, 0 },
     384             :     { "CELL",                   "CELL",                 125,    125,    1,  2,  V, { VV, RO }, FUNCFLAG_VOLATILE },
     385             :     { "ISERR",                  "ISERR",                126,    126,    1,  1,  V, { VR }, 0 },
     386             :     { "ISTEXT",                 "ISTEXT",               127,    127,    1,  1,  V, { VR }, 0 },
     387             :     { "ISNUMBER",               "ISNUMBER",             128,    128,    1,  1,  V, { VR }, 0 },
     388             :     { "ISBLANK",                "ISBLANK",              129,    129,    1,  1,  V, { VR }, 0 },
     389             :     { "T",                      "T",                    130,    130,    1,  1,  V, { RO }, 0 },
     390             :     { "N",                      "N",                    131,    131,    1,  1,  V, { RO }, 0 },
     391             :     { "DATEVALUE",              "DATEVALUE",            140,    140,    1,  1,  V, { VR }, 0 },
     392             :     { "TIMEVALUE",              "TIMEVALUE",            141,    141,    1,  1,  V, { VR }, 0 },
     393             :     { "SLN",                    "SLN",                  142,    142,    3,  3,  V, { VR }, 0 },
     394             :     { "SYD",                    "SYD",                  143,    143,    4,  4,  V, { VR }, 0 },
     395             :     { "DDB",                    "DDB",                  144,    144,    4,  5,  V, { VR }, 0 },
     396             :     { "INDIRECT",               "INDIRECT",             148,    148,    1,  2,  R, { VR }, FUNCFLAG_VOLATILE },
     397             :     { "CLEAN",                  "CLEAN",                162,    162,    1,  1,  V, { VR }, 0 },
     398             :     { "MDETERM",                "MDETERM",              163,    163,    1,  1,  V, { VA }, 0 },
     399             :     { "MINVERSE",               "MINVERSE",             164,    164,    1,  1,  A, { VA }, 0 },
     400             :     { "MMULT",                  "MMULT",                165,    165,    2,  2,  A, { VA }, 0 },
     401             :     { "IPMT",                   "IPMT",                 167,    167,    4,  6,  V, { VR }, 0 },
     402             :     { "PPMT",                   "PPMT",                 168,    168,    4,  6,  V, { VR }, 0 },
     403             :     { "COUNTA",                 "COUNTA",               169,    169,    0,  MX, V, { RX }, 0 },
     404             :     { "PRODUCT",                "PRODUCT",              183,    183,    0,  MX, V, { RX }, 0 },
     405             :     { "FACT",                   "FACT",                 184,    184,    1,  1,  V, { VR }, 0 },
     406             :     { "DPRODUCT",               "DPRODUCT",             189,    189,    3,  3,  V, { RO, RR }, 0 },
     407             :     { "ISNONTEXT",              "ISNONTEXT",            190,    190,    1,  1,  V, { VR }, 0 },
     408             :     { "STDEVP",                 "STDEVP",               193,    193,    1,  MX, V, { RX }, 0 },
     409             :     { "VARP",                   "VARP",                 194,    194,    1,  MX, V, { RX }, 0 },
     410             :     { "DSTDEVP",                "DSTDEVP",              195,    195,    3,  3,  V, { RO, RR }, 0 },
     411             :     { "DVARP",                  "DVARP",                196,    196,    3,  3,  V, { RO, RR }, 0 },
     412             :     { "TRUNC",                  "TRUNC",                197,    197,    1,  1,  V, { VR, C }, 0 },
     413             :     { "ISLOGICAL",              "ISLOGICAL",            198,    198,    1,  1,  V, { VR }, 0 },
     414             :     { "DCOUNTA",                "DCOUNTA",              199,    199,    3,  3,  V, { RO, RR }, 0 },
     415             :     { 0,                        "EXTERN.CALL",          255,    255,    1,  MX, R, { RO_E, RO }, FUNCFLAG_IMPORTONLY },
     416             : 
     417             :     // *** macro sheet commands ***
     418             : 
     419             :     { 0,                        "A1.R1C1",              30,     30,     0,  1,  V, { VR }, FUNCFLAG_MACROCMD },
     420             :     { 0,                        "RETURN",               55,     55,     0,  1,  R, { RO }, FUNCFLAG_MACROFUNC },
     421             :     { 0,                        "ABSREF",               79,     79,     2,  2,  R, { VR, RO }, FUNCFLAG_MACROFUNC },
     422             :     { 0,                        "ADD.ARROW",            81,     81,     0,  0,  V, {}, FUNCFLAG_MACROCMD },
     423             :     { 0,                        "ACTIVE.CELL",          94,     94,     0,  0,  R, {}, FUNCFLAG_MACROFUNC },
     424             :     { 0,                        "ACTIVATE",             103,    103,    0,  2,  V, { VR }, FUNCFLAG_MACROCMD },
     425             :     { 0,                        "ACTIVATE.NEXT",        104,    104,    0,  0,  V, {}, FUNCFLAG_MACROCMD },
     426             :     { 0,                        "ACTIVATE.PREV",        105,    105,    0,  0,  V, {}, FUNCFLAG_MACROCMD },
     427             :     { 0,                        "ADD.BAR",              151,    151,    0,  0,  V, {}, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR },
     428             :     { 0,                        "ADD.MENU",             152,    152,    2,  2,  V, { VR, RO }, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR },
     429             :     { 0,                        "ADD.COMMAND",          153,    153,    3,  3,  V, { VR, RO }, FUNCFLAG_MACROFUNC | FUNCFLAG_ALWAYSVAR }
     430             : };
     431             : 
     432             : /** Functions new in BIFF3. */
     433             : static const FunctionData saFuncTableBiff3[] =
     434             : {
     435             :     { "LINEST",                 "LINEST",               49,     49,     1,  4,  A, { RA, RA, VV }, 0 },             // BIFF2: 1-2, BIFF3: 1-4
     436             :     { "TREND",                  "TREND",                50,     50,     1,  4,  A, { RA, RA, RA, VV }, 0 },             // BIFF2: 1-3, BIFF3: 1-4
     437             :     { "LOGEST",                 "LOGEST",               51,     51,     1,  4,  A, { RA, RA, VV }, 0 },             // BIFF2: 1-2, BIFF3: 1-4
     438             :     { "GROWTH",                 "GROWTH",               52,     52,     1,  4,  A, { RA, RA, RA, VV }, 0 },             // BIFF2: 1-3, BIFF3: 1-4
     439             :     { "TRUNC",                  "TRUNC",                197,    197,    1,  2,  V, { VR }, 0 },                      // BIFF2: 1,   BIFF3: 1-2
     440             :     { "DOLLAR",                 "USDOLLAR",             204,    204,    1,  2,  V, { VR }, FUNCFLAG_IMPORTONLY },
     441             :     { 0/*"FIND"*/,              "FINDB",                205,    205,    2,  3,  V, { VR }, 0 },
     442             :     { 0/*"SEARCH"*/,            "SEARCHB",              206,    206,    2,  3,  V, { VR }, 0 },
     443             :     { 0/*"REPLACE"*/,           "REPLACEB",             207,    207,    4,  4,  V, { VR }, 0 },
     444             :     { "LEFTB",                  "LEFTB",                208,    208,    1,  2,  V, { VR }, 0 },
     445             :     { "RIGHTB",                 "RIGHTB",               209,    209,    1,  2,  V, { VR }, 0 },
     446             :     { "MIDB",                   "MIDB",                 210,    210,    3,  3,  V, { VR }, 0 },
     447             :     { "LENB",                   "LENB",                 211,    211,    1,  1,  V, { VR }, 0 },
     448             :     { "ROUNDUP",                "ROUNDUP",              212,    212,    2,  2,  V, { VR }, 0 },
     449             :     { "ROUNDDOWN",              "ROUNDDOWN",            213,    213,    2,  2,  V, { VR }, 0 },
     450             :     { "ASC",                    "ASC",                  214,    214,    1,  1,  V, { VR }, 0 },
     451             :     { "JIS",                    "DBCS",                 215,    215,    1,  1,  V, { VR }, 0 },
     452             :     { "ADDRESS",                "ADDRESS",              219,    219,    2,  5,  V, { VR }, 0 },
     453             :     { "DAYS360",                "DAYS360",              220,    220,    2,  2,  V, { VR, VR, C }, 0 },
     454             :     { "TODAY",                  "TODAY",                221,    221,    0,  0,  V, {}, FUNCFLAG_VOLATILE },
     455             :     { "VDB",                    "VDB",                  222,    222,    5,  7,  V, { VR }, 0 },
     456             :     { "MEDIAN",                 "MEDIAN",               227,    227,    1,  MX, V, { RX }, 0 },
     457             :     { "SUMPRODUCT",             "SUMPRODUCT",           228,    228,    1,  MX, V, { VA }, 0 },
     458             :     { "SINH",                   "SINH",                 229,    229,    1,  1,  V, { VR }, 0 },
     459             :     { "CSCH",                   "SINH",                 229,    229,    1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     460             :     { "COSH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, 0 },
     461             :     { "SECH",                   "COSH",                 230,    230,    1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     462             :     { "TANH",                   "TANH",                 231,    231,    1,  1,  V, { VR }, 0 },
     463             :     { "COTH",                   "TANH",                 231,    231,    1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     464             :     { "ASINH",                  "ASINH",                232,    232,    1,  1,  V, { VR }, 0 },
     465             :     { "ACOSH",                  "ACOSH",                233,    233,    1,  1,  V, { VR }, 0 },
     466             :     { "ATANH",                  "ATANH",                234,    234,    1,  1,  V, { VR }, 0 },
     467             :     { "ACOTH",                  "ATANH",                234,    234,    1,  1,  V, { VR }, FUNCFLAG_BIFFEXPORTONLY },
     468             :     { "DGET",                   "DGET",                 235,    235,    3,  3,  V, { RO, RR }, 0 },
     469             :     { "INFO",                   "INFO",                 244,    244,    1,  1,  V, { VR }, FUNCFLAG_VOLATILE },
     470             : 
     471             :     // *** macro sheet commands ***
     472             : 
     473             :     { 0,                        "ADD.BAR",              151,    151,    0,  1,  V, { VR }, FUNCFLAG_MACROFUNC },    // BIFF2: 0,   BIFF3: 0-1
     474             :     { 0,                        "ADD.MENU",             152,    152,    2,  3,  V, { VR, RO }, FUNCFLAG_MACROFUNC },  // BIFF2: 2,   BIFF3: 2-3
     475             :     { 0,                        "ADD.COMMAND",          153,    153,    3,  4,  V, { VR, RO }, FUNCFLAG_MACROFUNC }   // BIFF2: 3,   BIFF3: 3-4
     476             : };
     477             : 
     478             : /** Functions new in BIFF4. */
     479             : static const FunctionData saFuncTableBiff4[] =
     480             : {
     481             :     { "FIXED",                  "FIXED",                14,     14,     1,  3,  V, { VR }, 0 },       // BIFF2-3: 1-2, BIFF4: 1-3
     482             :     { "RANK",                   "RANK",                 216,    216,    2,  3,  V, { VR, RO, VR }, 0 },
     483             :     { "DB",                     "DB",                   247,    247,    4,  5,  V, { VR }, 0 },
     484             :     { "FREQUENCY",              "FREQUENCY",            252,    252,    2,  2,  A, { RA }, 0 },
     485             :     { "ORG.OPENOFFICE.ERRORTYPE","ERROR.TYPE",          261,    261,    1,  1,  V, { VR }, 0 },
     486             :     { "AVEDEV",                 "AVEDEV",               269,    269,    1,  MX, V, { RX }, 0 },
     487             :     { "BETADIST",               "BETADIST",             270,    270,    3,  5,  V, { VR }, 0 },
     488             :     { "GAMMALN",                "GAMMALN",              271,    271,    1,  1,  V, { VR }, 0 },
     489             :     { "BETAINV",                "BETAINV",              272,    272,    3,  5,  V, { VR }, 0 },
     490             :     { "BINOMDIST",              "BINOMDIST",            273,    273,    4,  4,  V, { VR }, 0 },
     491             :     { "LEGACY.CHIDIST",         "CHIDIST",              274,    274,    2,  2,  V, { VR }, 0 },
     492             :     { "LEGACY.CHIINV",          "CHIINV",               275,    275,    2,  2,  V, { VR }, 0 },
     493             :     { "COMBIN",                 "COMBIN",               276,    276,    2,  2,  V, { VR }, 0 },
     494             :     { "CONFIDENCE",             "CONFIDENCE",           277,    277,    3,  3,  V, { VR }, 0 },
     495             :     { "CRITBINOM",              "CRITBINOM",            278,    278,    3,  3,  V, { VR }, 0 },
     496             :     { "EVEN",                   "EVEN",                 279,    279,    1,  1,  V, { VR }, 0 },
     497             :     { "EXPONDIST",              "EXPONDIST",            280,    280,    3,  3,  V, { VR }, 0 },
     498             :     { "LEGACY.FDIST",           "FDIST",                281,    281,    3,  3,  V, { VR }, 0 },
     499             :     { "LEGACY.FINV",            "FINV",                 282,    282,    3,  3,  V, { VR }, 0 },
     500             :     { "FISHER",                 "FISHER",               283,    283,    1,  1,  V, { VR }, 0 },
     501             :     { "FISHERINV",              "FISHERINV",            284,    284,    1,  1,  V, { VR }, 0 },
     502             :     { "FLOOR",                  "FLOOR",                285,    285,    2,  2,  V, { VR, VR, C }, 0 },
     503             :     { "GAMMADIST",              "GAMMADIST",            286,    286,    4,  4,  V, { VR }, 0 },
     504             :     { "GAMMAINV",               "GAMMAINV",             287,    287,    3,  3,  V, { VR }, 0 },
     505             :     { "CEILING",                "CEILING",              288,    288,    2,  2,  V, { VR, VR, C }, 0 },
     506             :     { "HYPGEOMDIST",            "HYPGEOMDIST",          289,    289,    4,  4,  V, { VR }, 0 },
     507             :     { "LOGNORMDIST",            "LOGNORMDIST",          290,    290,    3,  3,  V, { VR }, 0 },
     508             :     { "LOGINV",                 "LOGINV",               291,    291,    3,  3,  V, { VR }, 0 },
     509             :     { "NEGBINOMDIST",           "NEGBINOMDIST",         292,    292,    3,  3,  V, { VR }, 0 },
     510             :     { "NORMDIST",               "NORMDIST",             293,    293,    4,  4,  V, { VR }, 0 },
     511             :     { "LEGACY.NORMSDIST",       "NORMSDIST",            294,    294,    1,  1,  V, { VR }, 0 },
     512             :     { "NORMINV",                "NORMINV",              295,    295,    3,  3,  V, { VR }, 0 },
     513             :     { "LEGACY.NORMSINV",        "NORMSINV",             296,    296,    1,  1,  V, { VR }, 0 },
     514             :     { "STANDARDIZE",            "STANDARDIZE",          297,    297,    3,  3,  V, { VR }, 0 },
     515             :     { "ODD",                    "ODD",                  298,    298,    1,  1,  V, { VR }, 0 },
     516             :     { "PERMUT",                 "PERMUT",               299,    299,    2,  2,  V, { VR }, 0 },
     517             :     { "POISSON",                "POISSON",              300,    300,    3,  3,  V, { VR }, 0 },
     518             :     { "LEGACY.TDIST",           "TDIST",                301,    301,    3,  3,  V, { VR }, 0 },
     519             :     { "WEIBULL",                "WEIBULL",              302,    302,    4,  4,  V, { VR }, 0 },
     520             :     { "SUMXMY2",                "SUMXMY2",              303,    303,    2,  2,  V, { VA }, 0 },
     521             :     { "SUMX2MY2",               "SUMX2MY2",             304,    304,    2,  2,  V, { VA }, 0 },
     522             :     { "SUMX2PY2",               "SUMX2PY2",             305,    305,    2,  2,  V, { VA }, 0 },
     523             :     { "LEGACY.CHITEST",         "CHITEST",              306,    306,    2,  2,  V, { VA }, 0 },
     524             :     { "CORREL",                 "CORREL",               307,    307,    2,  2,  V, { VA }, 0 },
     525             :     { "COVAR",                  "COVAR",                308,    308,    2,  2,  V, { VA }, 0 },
     526             :     { "FORECAST",               "FORECAST",             309,    309,    3,  3,  V, { VR, VA }, 0 },
     527             :     { "FTEST",                  "FTEST",                310,    310,    2,  2,  V, { VA }, 0 },
     528             :     { "INTERCEPT",              "INTERCEPT",            311,    311,    2,  2,  V, { VA }, 0 },
     529             :     { "PEARSON",                "PEARSON",              312,    312,    2,  2,  V, { VA }, 0 },
     530             :     { "RSQ",                    "RSQ",                  313,    313,    2,  2,  V, { VA }, 0 },
     531             :     { "STEYX",                  "STEYX",                314,    314,    2,  2,  V, { VA }, 0 },
     532             :     { "SLOPE",                  "SLOPE",                315,    315,    2,  2,  V, { VA }, 0 },
     533             :     { "TTEST",                  "TTEST",                316,    316,    4,  4,  V, { VA, VA, VR }, 0 },
     534             :     { "PROB",                   "PROB",                 317,    317,    3,  4,  V, { VA, VA, VR }, 0 },
     535             :     { "DEVSQ",                  "DEVSQ",                318,    318,    1,  MX, V, { RX }, 0 },
     536             :     { "GEOMEAN",                "GEOMEAN",              319,    319,    1,  MX, V, { RX }, 0 },
     537             :     { "HARMEAN",                "HARMEAN",              320,    320,    1,  MX, V, { RX }, 0 },
     538             :     { "SUMSQ",                  "SUMSQ",                321,    321,    0,  MX, V, { RX }, 0 },
     539             :     { "KURT",                   "KURT",                 322,    322,    1,  MX, V, { RX }, 0 },
     540             :     { "SKEW",                   "SKEW",                 323,    323,    1,  MX, V, { RX }, 0 },
     541             :     { "ZTEST",                  "ZTEST",                324,    324,    2,  3,  V, { RX, VR }, 0 },
     542             :     { "LARGE",                  "LARGE",                325,    325,    2,  2,  V, { RX, VR }, 0 },
     543             :     { "SMALL",                  "SMALL",                326,    326,    2,  2,  V, { RX, VR }, 0 },
     544             :     { "QUARTILE",               "QUARTILE",             327,    327,    2,  2,  V, { RX, VR }, 0 },
     545             :     { "PERCENTILE",             "PERCENTILE",           328,    328,    2,  2,  V, { RX, VR }, 0 },
     546             :     { "PERCENTRANK",            "PERCENTRANK",          329,    329,    2,  3,  V, { RX, VR, VR_E }, 0 },
     547             :     { "MODE",                   "MODE",                 330,    330,    1,  MX, V, { VA }, 0 },
     548             :     { "TRIMMEAN",               "TRIMMEAN",             331,    331,    2,  2,  V, { RX, VR }, 0 },
     549             :     { "TINV",                   "TINV",                 332,    332,    2,  2,  V, { VR }, 0 },
     550             : 
     551             :     // *** Analysis add-in ***
     552             : 
     553             :     { "HEX2BIN",                "HEX2BIN",              384,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     554             :     { "HEX2DEC",                "HEX2DEC",              385,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     555             :     { "HEX2OCT",                "HEX2OCT",              386,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     556             :     { "DEC2BIN",                "DEC2BIN",              387,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     557             :     { "DEC2HEX",                "DEC2HEX",              388,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     558             :     { "DEC2OCT",                "DEC2OCT",              389,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     559             :     { "OCT2BIN",                "OCT2BIN",              390,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     560             :     { "OCT2HEX",                "OCT2HEX",              391,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     561             :     { "OCT2DEC",                "OCT2DEC",              392,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     562             :     { "BIN2DEC",                "BIN2DEC",              393,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     563             :     { "BIN2OCT",                "BIN2OCT",              394,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     564             :     { "BIN2HEX",                "BIN2HEX",              395,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     565             :     { "IMSUB",                  "IMSUB",                396,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     566             :     { "IMDIV",                  "IMDIV",                397,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     567             :     { "IMPOWER",                "IMPOWER",              398,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     568             :     { "IMABS",                  "IMABS",                399,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     569             :     { "IMSQRT",                 "IMSQRT",               400,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     570             :     { "IMLN",                   "IMLN",                 401,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     571             :     { "IMLOG2",                 "IMLOG2",               402,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     572             :     { "IMLOG10",                "IMLOG10",              403,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     573             :     { "IMSIN",                  "IMSIN",                404,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     574             :     { "IMCOS",                  "IMCOS",                405,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     575             :     { "IMEXP",                  "IMEXP",                406,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     576             :     { "IMARGUMENT",             "IMARGUMENT",           407,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     577             :     { "IMCONJUGATE",            "IMCONJUGATE",          408,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     578             :     { "IMAGINARY",              "IMAGINARY",            409,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     579             :     { "IMREAL",                 "IMREAL",               410,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     580             :     { "COMPLEX",                "COMPLEX",              411,    NOID,   2,  3,  V, { RR }, FUNCFLAG_EXTERNAL },
     581             :     { "IMSUM",                  "IMSUM",                412,    NOID,   1,  MX, V, { RX }, FUNCFLAG_EXTERNAL },
     582             :     { "IMPRODUCT",              "IMPRODUCT",            413,    NOID,   1,  MX, V, { RX }, FUNCFLAG_EXTERNAL },
     583             :     { "SERIESSUM",              "SERIESSUM",            414,    NOID,   4,  4,  V, { RR, RR, RR, RX }, FUNCFLAG_EXTERNAL },
     584             :     { "FACTDOUBLE",             "FACTDOUBLE",           415,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     585             :     { "SQRTPI",                 "SQRTPI",               416,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     586             :     { "QUOTIENT",               "QUOTIENT",             417,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     587             :     { "DELTA",                  "DELTA",                418,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     588             :     { "GESTEP",                 "GESTEP",               419,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     589             :     { "ISEVEN",                 "ISEVEN",               420,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     590             :     { "ISODD",                  "ISODD",                421,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     591             :     { "MROUND",                 "MROUND",               422,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     592             :     { "ERF",                    "ERF",                  423,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     593             :     { "ERFC",                   "ERFC",                 424,    NOID,   1,  1,  V, { RR }, FUNCFLAG_EXTERNAL },
     594             :     { "BESSELJ",                "BESSELJ",              425,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     595             :     { "BESSELK",                "BESSELK",              426,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     596             :     { "BESSELY",                "BESSELY",              427,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     597             :     { "BESSELI",                "BESSELI",              428,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     598             :     { "XIRR",                   "XIRR",                 429,    NOID,   2,  3,  V, { RX, RX, RR }, FUNCFLAG_EXTERNAL },
     599             :     { "XNPV",                   "XNPV",                 430,    NOID,   3,  3,  V, { RR, RX, RX }, FUNCFLAG_EXTERNAL },
     600             :     { "PRICEMAT",               "PRICEMAT",             431,    NOID,   5,  6,  V, { RR }, FUNCFLAG_EXTERNAL },
     601             :     { "YIELDMAT",               "YIELDMAT",             432,    NOID,   5,  6,  V, { RR }, FUNCFLAG_EXTERNAL },
     602             :     { "INTRATE",                "INTRATE",              433,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     603             :     { "RECEIVED",               "RECEIVED",             434,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     604             :     { "DISC",                   "DISC",                 435,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     605             :     { "PRICEDISC",              "PRICEDISC",            436,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     606             :     { "YIELDDISC",              "YIELDDISC",            437,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     607             :     { "TBILLEQ",                "TBILLEQ",              438,    NOID,   3,  3,  V, { RR }, FUNCFLAG_EXTERNAL },
     608             :     { "TBILLPRICE",             "TBILLPRICE",           439,    NOID,   3,  3,  V, { RR }, FUNCFLAG_EXTERNAL },
     609             :     { "TBILLYIELD",             "TBILLYIELD",           440,    NOID,   3,  3,  V, { RR }, FUNCFLAG_EXTERNAL },
     610             :     { "PRICE",                  "PRICE",                441,    NOID,   6,  7,  V, { RR }, FUNCFLAG_EXTERNAL },
     611             :     { "YIELD",                  "YIELD",                442,    NOID,   6,  7,  V, { RR }, FUNCFLAG_EXTERNAL },
     612             :     { "DOLLARDE",               "DOLLARDE",             443,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     613             :     { "DOLLARFR",               "DOLLARFR",             444,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     614             :     { "NOMINAL",                "NOMINAL",              445,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     615             :     { "EFFECT",                 "EFFECT",               446,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     616             :     { "CUMPRINC",               "CUMPRINC",             447,    NOID,   6,  6,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     617             :     { "CUMIPMT",                "CUMIPMT",              448,    NOID,   6,  6,  V, { RR }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     618             :     { "EDATE",                  "EDATE",                449,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     619             :     { "EOMONTH",                "EOMONTH",              450,    NOID,   2,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     620             :     { "YEARFRAC",               "YEARFRAC",             451,    NOID,   2,  3,  V, { RR }, FUNCFLAG_EXTERNAL },
     621             :     { "COUPDAYBS",              "COUPDAYBS",            452,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     622             :     { "COUPDAYS",               "COUPDAYS",             453,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     623             :     { "COUPDAYSNC",             "COUPDAYSNC",           454,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     624             :     { "COUPNCD",                "COUPNCD",              455,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     625             :     { "COUPNUM",                "COUPNUM",              456,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     626             :     { "COUPPCD",                "COUPPCD",              457,    NOID,   3,  4,  V, { RR }, FUNCFLAG_EXTERNAL },
     627             :     { "DURATION",               "DURATION",             458,    NOID,   5,  6,  V, { RR }, FUNCFLAG_EXTERNAL }, // Calc: builtin and add-in (but different!)
     628             :     { "MDURATION",              "MDURATION",            459,    NOID,   5,  6,  V, { RR }, FUNCFLAG_EXTERNAL },
     629             :     { "ODDLPRICE",              "ODDLPRICE",            460,    NOID,   7,  8,  V, { RR }, FUNCFLAG_EXTERNAL },
     630             :     { "ODDLYIELD",              "ODDLYIELD",            461,    NOID,   8,  9,  V, { RR }, FUNCFLAG_EXTERNAL },
     631             :     { "ODDFPRICE",              "ODDFPRICE",            462,    NOID,   8,  9,  V, { RR }, FUNCFLAG_EXTERNAL },
     632             :     { "ODDFYIELD",              "ODDFYIELD",            463,    NOID,   8,  9,  V, { RR }, FUNCFLAG_EXTERNAL },
     633             :     { "RANDBETWEEN",            "RANDBETWEEN",          464,    NOID,   2,  2,  V, { RR }, FUNCFLAG_VOLATILE | FUNCFLAG_EXTERNAL },
     634             :     { "WEEKNUM",                "WEEKNUM",              465,    NOID,   1,  2,  V, { RR }, FUNCFLAG_EXTERNAL },
     635             :     { "AMORDEGRC",              "AMORDEGRC",            466,    NOID,   6,  7,  V, { RR }, FUNCFLAG_EXTERNAL },
     636             :     { "AMORLINC",               "AMORLINC",             467,    NOID,   6,  7,  V, { RR }, FUNCFLAG_EXTERNAL },
     637             :     { "CONVERT",                "CONVERT",              468,    NOID,   3,  3,  V, { RR }, FUNCFLAG_EXTERNAL },       // Calc: builtin and add-in (but different!)
     638             :     { "ACCRINT",                "ACCRINT",              469,    NOID,   6,  7,  V, { RR }, FUNCFLAG_EXTERNAL },
     639             :     { "ACCRINTM",               "ACCRINTM",             470,    NOID,   4,  5,  V, { RR }, FUNCFLAG_EXTERNAL },
     640             :     { "WORKDAY",                "WORKDAY",              471,    NOID,   2,  3,  V, { RR, RR, RX, C }, FUNCFLAG_EXTERNAL },
     641             :     { "NETWORKDAYS",            "NETWORKDAYS",          472,    NOID,   2,  3,  V, { RR, RR, RX, C }, FUNCFLAG_EXTERNAL },
     642             :     { "GCD",                    "GCD",                  473,    NOID,   1,  MX, V, { RX }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     643             :     { "MULTINOMIAL",            "MULTINOMIAL",          474,    NOID,   1,  MX, V, { RX }, FUNCFLAG_EXTERNAL },
     644             :     { "LCM",                    "LCM",                  475,    NOID,   1,  MX, V, { RX }, FUNCFLAG_EXTERNAL | FUNCFLAG_INTERNAL }, // Calc: builtin and add-in
     645             :     { "FVSCHEDULE",             "FVSCHEDULE",           476,    NOID,   2,  2,  V, { RR, RX }, FUNCFLAG_EXTERNAL },
     646             : 
     647             :     // *** macro sheet commands ***
     648             : 
     649             :     { 0,                        "ACTIVATE.NEXT",        104,    104,    0,  1,  V, { VR }, FUNCFLAG_MACROCMD },      // BIFF2-3: 0, BIFF4: 0-1
     650             :     { 0,                        "ACTIVATE.PREV",        105,    105,    0,  1,  V, { VR }, FUNCFLAG_MACROCMD }       // BIFF2-3: 0, BIFF4: 0-1
     651             : };
     652             : 
     653             : /** Functions new in BIFF5/BIFF7. */
     654             : static const FunctionData saFuncTableBiff5[] =
     655             : {
     656             :     { "WEEKDAY",                "WEEKDAY",              70,     70,     1,  2,  V, { VR }, 0 },                              // BIFF2-4: 1,   BIFF5: 1-2
     657             :     { "HLOOKUP",                "HLOOKUP",              101,    101,    3,  4,  V, { VV, RO, RO, VV }, 0 },                     // BIFF2-4: 3,   BIFF5: 3-4
     658             :     { "VLOOKUP",                "VLOOKUP",              102,    102,    3,  4,  V, { VV, RO, RO, VV }, 0 },                     // BIFF2-4: 3,   BIFF5: 3-4
     659             :     { "DAYS360",                "DAYS360",              220,    220,    2,  3,  V, { VR }, 0 },                              // BIFF3-4: 2,   BIFF5: 2-3
     660             :     { 0,                        "EXTERN.CALL",          255,    255,    1,  MX, R, { RO_E, RO }, FUNCFLAG_EXPORTONLY },        // MACRO or EXTERNAL
     661             :     { "CONCATENATE",            "CONCATENATE",          336,    336,    0,  MX, V, { VR }, 0 },
     662             :     { "POWER",                  "POWER",                337,    337,    2,  2,  V, { VR }, 0 },
     663             :     { "RADIANS",                "RADIANS",              342,    342,    1,  1,  V, { VR }, 0 },
     664             :     { "DEGREES",                "DEGREES",              343,    343,    1,  1,  V, { VR }, 0 },
     665             :     { "SUBTOTAL",               "SUBTOTAL",             344,    344,    2,  MX, V, { VR, RO }, 0 },
     666             :     { "SUMIF",                  "SUMIF",                345,    345,    2,  3,  V, { RO, VR, RO }, 0 },
     667             :     { "COUNTIF",                "COUNTIF",              346,    346,    2,  2,  V, { RO, VR }, 0 },
     668             :     { "COUNTBLANK",             "COUNTBLANK",           347,    347,    1,  1,  V, { RO }, 0 },
     669             :     { "ISPMT",                  "ISPMT",                350,    350,    4,  4,  V, { VR }, 0 },
     670             :     { "DATEDIF",                "DATEDIF",              351,    351,    3,  3,  V, { VR }, 0 },
     671             :     { 0,                        "DATESTRING",           352,    352,    1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY },   // not supported in Calc, missing in OOXML spec
     672             :     { 0,                        "NUMBERSTRING",         353,    353,    2,  2,  V, { VR }, FUNCFLAG_IMPORTONLY },   // not supported in Calc, missing in OOXML spec
     673             :     { "ROMAN",                  "ROMAN",                354,    354,    1,  2,  V, { VR }, 0 },
     674             : 
     675             :     // *** EuroTool add-in ***
     676             : 
     677             :     { "EUROCONVERT",            "EUROCONVERT",          NOID,   NOID,   3,  5,  V, { VR }, FUNCLIB_TO_FUNCFLAGS( FUNCLIB_EUROTOOL ) },
     678             : 
     679             :     // *** macro sheet commands ***
     680             : 
     681             :     { 0,                        "ADD.MENU",             152,    152,    2,  4,  V, { VR, RO, RO, VR }, FUNCFLAG_MACROFUNC },    // BIFF3-4: 2-3, BIFF5: 2-4
     682             :     { 0,                        "ADD.COMMAND",          153,    153,    3,  5,  V, { VR, RO, RO, RO, VR }, FUNCFLAG_MACROFUNC }, // BIFF3-4: 3-4, BIFF5: 3-5
     683             :     { 0,                        "ADD.CHART.AUTOFORMAT", 390,    390,    0,  2,  V, { VR }, FUNCFLAG_MACROCMD },
     684             :     { 0,                        "ADD.LIST.ITEM",        451,    451,    0,  2,  V, { VR }, FUNCFLAG_MACROCMD },
     685             :     { 0,                        "ACTIVE.CELL.FONT",     476,    476,    0,  14, V, { VR }, FUNCFLAG_MACROCMD }
     686             : };
     687             : 
     688             : /** Functions new in BIFF8. */
     689             : static const FunctionData saFuncTableBiff8[] =
     690             : {
     691             :     { "GETPIVOTDATA",           "GETPIVOTDATA",         358,    358,    2,  MX, V, { RR, RR, VR, VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_PARAMPAIRS },
     692             :     { "HYPERLINK",              "HYPERLINK",            359,    359,    1,  2,  V, { VV, VO }, 0 },
     693             :     { 0,                        "PHONETIC",             360,    360,    1,  1,  V, { RO }, FUNCFLAG_IMPORTONLY },
     694             :     { "AVERAGEA",               "AVERAGEA",             361,    361,    1,  MX, V, { RX }, 0 },
     695             :     { "MAXA",                   "MAXA",                 362,    362,    1,  MX, V, { RX }, 0 },
     696             :     { "MINA",                   "MINA",                 363,    363,    1,  MX, V, { RX }, 0 },
     697             :     { "STDEVPA",                "STDEVPA",              364,    364,    1,  MX, V, { RX }, 0 },
     698             :     { "VARPA",                  "VARPA",                365,    365,    1,  MX, V, { RX }, 0 },
     699             :     { "STDEVA",                 "STDEVA",               366,    366,    1,  MX, V, { RX }, 0 },
     700             :     { "VARA",                   "VARA",                 367,    367,    1,  MX, V, { RX }, 0 },
     701             :     { "COM.MICROSOFT.BAHTTEXT", "BAHTTEXT",             368,    368,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     702             :     { 0,                        "THAIDAYOFWEEK",        369,    369,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     703             :     { 0,                        "THAIDIGIT",            370,    370,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     704             :     { 0,                        "THAIMONTHOFYEAR",      371,    371,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     705             :     { 0,                        "THAINUMSOUND",         372,    372,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     706             :     { 0,                        "THAINUMSTRING",        373,    373,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     707             :     { 0,                        "THAISTRINGLENGTH",     374,    374,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     708             :     { 0,                        "ISTHAIDIGIT",          375,    375,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     709             :     { 0,                        "ROUNDBAHTDOWN",        376,    376,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     710             :     { 0,                        "ROUNDBAHTUP",          377,    377,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     711             :     { 0,                        "THAIYEAR",             378,    378,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL },
     712             :     { 0,                        "RTD",                  379,    379,    3,  3,  A, { VR, VR, RO }, 0 }
     713             : };
     714             : 
     715             : /** Functions new in OOXML. */
     716             : static const FunctionData saFuncTableOox[] =
     717             : {
     718             :     { 0,                        "CUBEVALUE",            380,    NOID,   1,  MX, V, { VR, RX }, 0 },
     719             :     { 0,                        "CUBEMEMBER",           381,    NOID,   2,  3,  V, { VR, RX, VR }, 0 },
     720             :     { 0,                        "CUBEMEMBERPROPERTY",   382,    NOID,   3,  3,  V, { VR }, 0 },
     721             :     { 0,                        "CUBERANKEDMEMBER",     383,    NOID,   3,  4,  V, { VR }, 0 },
     722             :     { 0,                        "CUBEKPIMEMBER",        477,    NOID,   3,  4,  V, { VR }, 0 },
     723             :     { 0,                        "CUBESET",              478,    NOID,   2,  5,  V, { VR, RX, VR }, 0 },
     724             :     { 0,                        "CUBESETCOUNT",         479,    NOID,   1,  1,  V, { VR }, 0 },
     725             :     { "IFERROR",                "IFERROR",              480,    NOID,   2,  2,  V, { VO, RO }, FUNCFLAG_MACROCALL },
     726             :     { "COUNTIFS",               "COUNTIFS",             481,    NOID,   2,  MX, V, { RO, VR }, FUNCFLAG_MACROCALL | FUNCFLAG_PARAMPAIRS },
     727             :     { "SUMIFS",                 "SUMIFS",               482,    NOID,   3,  MX, V, { RO, RO, VR }, FUNCFLAG_MACROCALL | FUNCFLAG_PARAMPAIRS },
     728             :     { "AVERAGEIF",              "AVERAGEIF",            483,    NOID,   2,  3,  V, { RO, VR, RO }, FUNCFLAG_MACROCALL },
     729             :     { "AVERAGEIFS",             "AVERAGEIFS",           484,    NOID,   3,  MX, V, { RO, RO, VR }, FUNCFLAG_MACROCALL | FUNCFLAG_PARAMPAIRS },
     730             :     { "COM.MICROSOFT.ISO.CEILING",  "ISO.CEILING",     NOID,    NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL },
     731             :     { "COM.MICROSOFT.NETWORKDAYS.INTL", "NETWORKDAYS.INTL", NOID, NOID, 2,  4,  V, { VR, VR, VR, RX }, FUNCFLAG_MACROCALL },
     732             :     { "COM.MICROSOFT.WORKDAY.INTL",     "WORKDAY.INTL",     NOID, NOID, 2,  4,  V, { VR, VR, VR, RX }, FUNCFLAG_MACROCALL }
     733             : };
     734             : 
     735             : /** Functions new in Excel 2010.
     736             : 
     737             :     A lot of statistical functions have been renamed (although the 'old' function name still is valid).
     738             :     See http://office.microsoft.com/en-us/excel-help/what-s-new-changes-made-to-excel-functions-HA010355760.aspx
     739             : 
     740             :     Functions with FUNCFLAG_IMPORTONLY are rewritten in
     741             :     sc/source/filter/excel/xeformula.cxx during export for
     742             :     BIFF, OOXML export uses this different mapping here but still uses the
     743             :     mapping there to determine the feature set.
     744             : 
     745             :     FIXME: either have the exporter determine the feature set from the active
     746             :     mapping, preferred, or enhance that mapping there such that for OOXML the
     747             :     rewrite can be overridden.
     748             : 
     749             :     @See sc/source/filter/excel/xlformula.cxx saFuncTable_2010
     750             :  */
     751             : /* FIXME: BIFF12 function identifiers available? Where to obtain? */
     752             : static const FunctionData saFuncTable2010[] =
     753             : {
     754             :     { "COM.MICROSOFT.COVARIANCE.P",           "COVARIANCE.P",        NOID,    NOID,   2,  2,  V, { VA }, FUNCFLAG_MACROCALL_NEW },
     755             :     { "COM.MICROSOFT.COVARIANCE.S",           "COVARIANCE.S",        NOID,    NOID,   2,  2,  V, { VA }, FUNCFLAG_MACROCALL_NEW },
     756             :     { "COM.MICROSOFT.STDEV.P",                "STDEV.P",             NOID,    NOID,   1, MX,  V, { RX }, FUNCFLAG_MACROCALL_NEW },
     757             :     { "COM.MICROSOFT.STDEV.S",                "STDEV.S",             NOID,    NOID,   1, MX,  V, { RX }, FUNCFLAG_MACROCALL_NEW },
     758             :     { "COM.MICROSOFT.VAR.P",                  "VAR.P"  ,             NOID,    NOID,   1, MX,  V, { RX }, FUNCFLAG_MACROCALL_NEW },
     759             :     { "COM.MICROSOFT.VAR.S",                  "VAR.S",               NOID,    NOID,   1, MX,  V, { RX }, FUNCFLAG_MACROCALL_NEW },
     760             :     { "COM.MICROSOFT.BETA.DIST",              "BETA.DIST"  ,         NOID,    NOID,   4,  6,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     761             :     { "COM.MICROSOFT.BETA.INV",               "BETA.INV",            NOID,    NOID,   3,  5,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     762             :     { "COM.MICROSOFT.BINOM.DIST",             "BINOM.DIST",          NOID,    NOID,   4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     763             :     { "COM.MICROSOFT.BINOM.INV",              "BINOM.INV",           NOID,    NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     764             :     { "COM.MICROSOFT.CHISQ.DIST",             "CHISQ.DIST",          NOID,    NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     765             :     { "COM.MICROSOFT.CHISQ.INV",              "CHISQ.INV",           NOID,    NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     766             :     { "COM.MICROSOFT.CHISQ.DIST.RT",          "CHISQ.DIST.RT",       NOID,    NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     767             :     { "COM.MICROSOFT.CHISQ.INV.RT",           "CHISQ.INV.RT",        NOID,    NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     768             :     { "COM.MICROSOFT.CHISQ.TEST",             "CHISQ.TEST",          NOID,    NOID,   2,  2,  V, { VA }, FUNCFLAG_MACROCALL_NEW },
     769             :     { "COM.MICROSOFT.CONFIDENCE.NORM",        "CONFIDENCE.NORM",     NOID,    NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     770             :     { "COM.MICROSOFT.CONFIDENCE.T",           "CONFIDENCE.T",        NOID,    NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     771             :     { "COM.MICROSOFT.F.DIST",                 "F.DIST",              NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     772             :     { "COM.MICROSOFT.F.DIST.RT",              "F.DIST.RT",           NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     773             :     { "COM.MICROSOFT.F.INV",                  "F.INV",               NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     774             :     { "COM.MICROSOFT.F.INV.RT",               "F.INV.RT",            NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     775             :     { "COM.MICROSOFT.F.TEST",                 "F.TEST",              NOID,   NOID,    2,  2,  V, { VA }, FUNCFLAG_MACROCALL_NEW },
     776             :     { "COM.MICROSOFT.EXPON.DIST",             "EXPON.DIST",          NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     777             :     { "COM.MICROSOFT.HYPGEOM.DIST",           "HYPGEOM.DIST",        NOID,   NOID,    5,  5,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     778             :     { "COM.MICROSOFT.POISSON.DIST",           "POISSON.DIST",        NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     779             :     { "COM.MICROSOFT.WEIBULL.DIST",           "WEIBULL.DIST",        NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     780             :     { "COM.MICROSOFT.GAMMA.DIST",             "GAMMA.DIST",          NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     781             :     { "COM.MICROSOFT.GAMMA.INV",              "GAMMA.INV",           NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     782             :     { "COM.MICROSOFT.GAMMALN.PRECISE",        "GAMMALN.PRECISE",     NOID,   NOID,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     783             :     { "COM.MICROSOFT.LOGNORM.DIST",           "LOGNORM.DIST",        NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     784             :     { "COM.MICROSOFT.LOGNORM.INV",            "LOGNORM.INV",         NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     785             :     { "COM.MICROSOFT.NORM.DIST",              "NORM.DIST",           NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     786             :     { "COM.MICROSOFT.NORM.INV",               "NORM.INV",            NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     787             :     { "COM.MICROSOFT.NORM.S.DIST",            "NORM.S.DIST",         NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     788             :     { "COM.MICROSOFT.NORM.S.INV",             "NORM.S.INV",          NOID,   NOID,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     789             :     { "COM.MICROSOFT.T.DIST",                 "T.DIST",              NOID,   NOID,    3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     790             :     { "COM.MICROSOFT.T.DIST.2T",              "T.DIST.2T",           NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     791             :     { "COM.MICROSOFT.T.DIST.RT",              "T.DIST.RT",           NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     792             :     { "COM.MICROSOFT.T.INV",                  "T.INV",               NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     793             :     { "COM.MICROSOFT.T.INV.2T",               "T.INV.2T",            NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     794             :     { "COM.MICROSOFT.T.TEST",                 "T.TEST",              NOID,   NOID,    4,  4,  V, { VA, VA, VR }, FUNCFLAG_MACROCALL_NEW },
     795             :     { "COM.MICROSOFT.PERCENTILE.INC",         "PERCENTILE.INC",      NOID,   NOID,    2,  2,  V, { RX, VR }, FUNCFLAG_MACROCALL_NEW },
     796             :     { "COM.MICROSOFT.PERCENTRANK.INC",        "PERCENTRANK.INC",     NOID,   NOID,    2,  3,  V, { RX, VR, VR_E }, FUNCFLAG_MACROCALL_NEW },
     797             :     { "COM.MICROSOFT.QUARTILE.INC",           "QUARTILE.INC",        NOID,   NOID,    2,  2,  V, { RX, VR }, FUNCFLAG_MACROCALL_NEW },
     798             :     { "COM.MICROSOFT.RANK.EQ",                "RANK.EQ",             NOID,   NOID,    2,  3,  V, { VR, RO, VR }, FUNCFLAG_MACROCALL_NEW },
     799             :     { "COM.MICROSOFT.PERCENTILE.EXC",         "PERCENTILE.EXC",      NOID,   NOID,    2,  2,  V, { RX, VR }, FUNCFLAG_MACROCALL_NEW },
     800             :     { "COM.MICROSOFT.PERCENTRANK.EXC",        "PERCENTRANK.EXC",     NOID,   NOID,    2,  3,  V, { RX, VR, VR_E }, FUNCFLAG_MACROCALL_NEW },
     801             :     { "COM.MICROSOFT.QUARTILE.EXC",           "QUARTILE.EXC",        NOID,   NOID,    2,  2,  V, { RX, VR }, FUNCFLAG_MACROCALL_NEW },
     802             :     { "COM.MICROSOFT.RANK.AVG",               "RANK.AVG",            NOID,   NOID,    2,  3,  V, { VR, RO, VR }, FUNCFLAG_MACROCALL_NEW },
     803             :     { "COM.MICROSOFT.MODE.SNGL",              "MODE.SNGL",           NOID,   NOID,    1,  MX, V, { VA }, FUNCFLAG_MACROCALL_NEW },
     804             :     { "COM.MICROSOFT.MODE.MULT",              "MODE.MULT",           NOID,   NOID,    1,  MX, V, { VA }, FUNCFLAG_MACROCALL_NEW },
     805             :     { "COM.MICROSOFT.NEGBINOM.DIST",          "NEGBINOM.DIST",       NOID,   NOID,    4,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     806             :     { "COM.MICROSOFT.Z.TEST",                 "Z.TEST",              NOID,   NOID,    2,  3,  V, { RX, VR }, FUNCFLAG_MACROCALL_NEW },
     807             :     { "COM.MICROSOFT.CEILING.PRECISE",        "CEILING.PRECISE",     NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     808             :     { "COM.MICROSOFT.FLOOR.PRECISE",          "FLOOR.PRECISE",       NOID,   NOID,    2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     809             :     { "COM.MICROSOFT.ERF.PRECISE",            "ERF.PRECISE",         NOID,   NOID,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     810             :     { "COM.MICROSOFT.ERFC.PRECISE",           "ERFC.PRECISE",        NOID,   NOID,    1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     811             :     { "COM.MICROSOFT.AGGREGATE",              "AGGREGATE",           NOID,   NOID,    3,  MX, V, { VR, RO }, FUNCFLAG_MACROCALL_NEW }
     812             : };
     813             : 
     814             : /** Functions new in Excel 2013.
     815             : 
     816             :     See http://office.microsoft.com/en-us/excel-help/new-functions-in-excel-2013-HA103980604.aspx
     817             :     Most functions apparently were added for ODF1.2 ODFF / OpenFormula
     818             :     compatibility.
     819             : 
     820             :     Functions with FUNCFLAG_IMPORTONLY are rewritten in
     821             :     sc/source/filter/excel/xeformula.cxx during export for
     822             :     BIFF, OOXML export uses this different mapping here but still uses the
     823             :     mapping there to determine the feature set.
     824             : 
     825             :     FIXME: either have the exporter determine the feature set from the active
     826             :     mapping, preferred, or enhance that mapping there such that for OOXML the
     827             :     rewrite can be overridden.
     828             : 
     829             :     @See sc/source/filter/excel/xlformula.cxx saFuncTable_2013
     830             :  */
     831             : /* FIXME: BIFF12 function identifiers available? Where to obtain? */
     832             : static const FunctionData saFuncTable2013[] =
     833             : {
     834             :     { "ACOT",                   "ACOT",                 NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     835             :     { "ACOTH",                  "ACOTH",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     836             :     { "ARABIC",                 "ARABIC",               NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     837             :     { "BASE",                   "BASE",                 NOID,   NOID,   2,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     838             :     { "BINOM.DIST.RANGE",       "BINOM.DIST.RANGE",     NOID,   NOID,   3,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     839             :     { "BITAND",                 "BITAND",               NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     840             :     { "BITLSHIFT",              "BITLSHIFT",            NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     841             :     { "BITOR",                  "BITOR",                NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     842             :     { "BITRSHIFT",              "BITRSHIFT",            NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     843             :     { "BITXOR",                 "BITXOR",               NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     844             :     /* FIXME: CEILING.MATH is our/ODFF CEILING, but we have special handling
     845             :      * for the weird Excel CEILING behavior, check that and unify or diversify.
     846             :      * */
     847             :     { 0/*"CEILING"*/,           "CEILING.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     848             :     { "COMBINA",                "COMBINA",              NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     849             :     { "COT",                    "COT",                  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     850             :     { "COTH",                   "COTH",                 NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     851             :     { "CSC",                    "CSC",                  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     852             :     { "CSCH",                   "CSCH",                 NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     853             :     { "DAYS",                   "DAYS",                 NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     854             :     { "DECIMAL",                "DECIMAL",              NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     855             :     { 0,                        "ENCODEURL",            NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     856             :     { "COM.MICROSOFT.FILTERXML","FILTERXML",            NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     857             :     /* FIXME: FLOOR.MATH is our/ODFF FLOOR, but we have special handling for
     858             :      * the weird Excel FLOOR behavior, check that and unify or diversify. */
     859             :     { 0/*"FLOOR"*/,             "FLOOR.MATH",           NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     860             :     // NOTE: this FDIST is not our LEGACY.FDIST
     861             :     { 0/*"FDIST"*/,             "FDIST",                NOID,   NOID,   3,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     862             :     // NOTE: this FINV is not our LEGACY.FINV
     863             :     { 0/*"FINV"*/,              "FINV",                 NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     864             :     { "FORMULA",                "FORMULATEXT",          NOID,   NOID,   1,  1,  V, { RO }, FUNCFLAG_MACROCALL_NEW },
     865             :     { "GAMMA",                  "GAMMA",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     866             :     { "GAUSS",                  "GAUSS",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     867             :     { "IFNA",                   "IFNA",                 NOID,   NOID,   2,  2,  V, { VO, RO }, FUNCFLAG_MACROCALL_NEW },
     868             :     { "IMCOSH",                 "IMCOSH",               NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     869             :     { "IMCOT",                  "IMCOT",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     870             :     { "IMCSC",                  "IMCSC",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     871             :     { "IMCSCH",                 "IMCSCH",               NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     872             :     { "IMSEC",                  "IMSEC",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     873             :     { "IMSECH",                 "IMSECH",               NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     874             :     { "IMSINH",                 "IMSINH",               NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     875             :     { "IMTAN",                  "IMTAN",                NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     876             :     { "ISFORMULA",              "ISFORMULA",            NOID,   NOID,   1,  1,  V, { RO }, FUNCFLAG_MACROCALL_NEW },
     877             :     /* FIXME: ISOWEEKNUM vs. WEEKNUM mess needs to be sorted out before we can
     878             :      * import. */
     879             :     { 0/*"ISOWEEKNUM"*/,        "ISOWEEKNUM",           NOID,   NOID,   1,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     880             :     { "MUNIT",                  "MUNIT",                NOID,   NOID,   1,  1,  A, { VR }, FUNCFLAG_MACROCALL_NEW },
     881             :     { "NUMBERVALUE",            "NUMBERVALUE",          NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     882             :     { "PDURATION",              "PDURATION",            NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     883             :     { "PERMUTATIONA",           "PERMUTATIONA",         NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     884             :     { "PHI",                    "PHI",                  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     885             :     { "RRI",                    "RRI",                  NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     886             :     { "SEC",                    "SEC",                  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     887             :     { "SECH",                   "SECH",                 NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     888             :     { "SHEET",                  "SHEET",                NOID,   NOID,   0,  1,  V, { RO }, FUNCFLAG_MACROCALL_NEW },
     889             :     { "SHEETS",                 "SHEETS",               NOID,   NOID,   0,  1,  V, { RO }, FUNCFLAG_MACROCALL_NEW },
     890             :     { "SKEWP",                  "SKEW.P",               NOID,   NOID,   1,  MX, V, { RX }, FUNCFLAG_MACROCALL_NEW },
     891             :     { "UNICHAR",                "UNICHAR",              NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     892             :     { "UNICODE",                "UNICODE",              NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     893             :     { "COM.MICROSOFT.WEBSERVICE","WEBSERVICE",          NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     894             :     { "XOR",                    "XOR",                  NOID,   NOID,   1,  MX, V, { RX }, FUNCFLAG_MACROCALL_NEW }
     895             : };
     896             : 
     897             : /** Functions defined by OpenFormula, but not supported by Calc or by Excel. */
     898             : static const FunctionData saFuncTableOdf[] =
     899             : {
     900             :     { "CHISQDIST",              0,                      NOID,   NOID,   2,  3,  V, { VR }, FUNCFLAG_MACROCALLODF },
     901             :     { "CHISQINV",               0,                      NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALLODF }
     902             : };
     903             : 
     904             : /** Functions defined by Calc, but not in OpenFormula nor supported by Excel. */
     905             : static const FunctionData saFuncTableOOoLO[] =
     906             : {
     907             :     { "ORG.OPENOFFICE.WEEKS",       "ORG.OPENOFFICE.WEEKS",       NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     908             :     { "ORG.OPENOFFICE.MONTHS",      "ORG.OPENOFFICE.MONTHS",      NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     909             :     { "ORG.OPENOFFICE.YEARS",       "ORG.OPENOFFICE.YEARS",       NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     910             :     { "ORG.OPENOFFICE.ISLEAPYEAR",  "ORG.OPENOFFICE.ISLEAPYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     911             :     { "ORG.OPENOFFICE.DAYSINMONTH", "ORG.OPENOFFICE.DAYSINMONTH", NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     912             :     { "ORG.OPENOFFICE.DAYSINYEAR",  "ORG.OPENOFFICE.DAYSINYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     913             :     { "ORG.OPENOFFICE.WEEKSINYEAR", "ORG.OPENOFFICE.WEEKSINYEAR", NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     914             :     { "ORG.OPENOFFICE.ROT13",       "ORG.OPENOFFICE.ROT13",       NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW | FUNCFLAG_EXTERNAL },
     915             :     /* Next 8 lines are for importing from .xlsx files saved by Calc before
     916             :      * fdo#59727 was patched with the entries above. */
     917             :     { "ORG.OPENOFFICE.WEEKS",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFWEEKS",   NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     918             :     { "ORG.OPENOFFICE.MONTHS",      "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFMONTHS",  NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     919             :     { "ORG.OPENOFFICE.YEARS",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDIFFYEARS",   NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     920             :    { "ORG.OPENOFFICE.ISLEAPYEAR",   "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETISLEAPYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     921             :     { "ORG.OPENOFFICE.DAYSINMONTH", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINMONTH", NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     922             :     { "ORG.OPENOFFICE.DAYSINYEAR",  "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETDAYSINYEAR",  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     923             :     { "ORG.OPENOFFICE.WEEKSINYEAR", "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETWEEKSINYEAR", NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     924             :     { "ORG.OPENOFFICE.ROT13",       "COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETROT13",       NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_IMPORTONLY | FUNCFLAG_EXTERNAL },
     925             :     // Other functions.
     926             :     { "ORG.OPENOFFICE.CONVERT",     "ORG.OPENOFFICE.CONVERT",   NOID,   NOID,   3,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     927             :     { "ORG.LIBREOFFICE.COLOR",      "ORG.LIBREOFFICE.COLOR",    NOID,   NOID,   3,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW }
     928             : };
     929             : 
     930             : const sal_Unicode API_TOKEN_OPEN            = '(';
     931             : const sal_Unicode API_TOKEN_CLOSE           = ')';
     932             : const sal_Unicode API_TOKEN_SEP             = ';';
     933             : 
     934             : const sal_Unicode API_TOKEN_ARRAY_OPEN      = '{';
     935             : const sal_Unicode API_TOKEN_ARRAY_CLOSE     = '}';
     936             : const sal_Unicode API_TOKEN_ARRAY_ROWSEP    = '|';
     937             : const sal_Unicode API_TOKEN_ARRAY_COLSEP    = ';';
     938             : 
     939             : } // namespace
     940             : 
     941             : // function info parameter class iterator =====================================
     942             : 
     943           0 : FunctionParamInfoIterator::FunctionParamInfoIterator( const FunctionInfo& rFuncInfo ) :
     944             :     mpParamInfo( rFuncInfo.mpParamInfos ),
     945           0 :     mpParamInfoEnd( rFuncInfo.mpParamInfos + FUNCINFO_PARAMINFOCOUNT ),
     946           0 :     mbParamPairs( rFuncInfo.mbParamPairs )
     947             : {
     948           0 : }
     949             : 
     950           0 : bool FunctionParamInfoIterator::isCalcOnlyParam() const
     951             : {
     952           0 :     return mpParamInfo && (mpParamInfo->meValid == FUNC_PARAM_CALCONLY);
     953             : }
     954             : 
     955           0 : bool FunctionParamInfoIterator::isExcelOnlyParam() const
     956             : {
     957           0 :     return mpParamInfo && (mpParamInfo->meValid == FUNC_PARAM_EXCELONLY);
     958             : }
     959             : 
     960           0 : FunctionParamInfoIterator& FunctionParamInfoIterator::operator++()
     961             : {
     962           0 :     if( mpParamInfo )
     963             :     {
     964             :         // move pointer to next entry, if something explicit follows
     965           0 :         if( (mpParamInfo + 1 < mpParamInfoEnd) && (mpParamInfo[ 1 ].meValid != FUNC_PARAM_NONE) )
     966           0 :             ++mpParamInfo;
     967             :         // if last parameter type is 'Excel-only' or 'Calc-only', do not repeat it
     968           0 :         else if( isExcelOnlyParam() || isCalcOnlyParam() )
     969           0 :             mpParamInfo = 0;
     970             :         // points to last info, but parameter pairs expected, move to previous info
     971           0 :         else if( mbParamPairs )
     972           0 :             --mpParamInfo;
     973             :         // otherwise: repeat last parameter class
     974             :     }
     975           0 :     return *this;
     976             : }
     977             : 
     978             : // function provider ==========================================================
     979             : 
     980         426 : struct FunctionProviderImpl
     981             : {
     982             :     typedef RefMap< OUString, FunctionInfo >    FuncNameMap;
     983             :     typedef RefMap< sal_uInt16, FunctionInfo >  FuncIdMap;
     984             : 
     985             :     FunctionInfoVector  maFuncs;            /// All function infos in one list.
     986             :     FuncNameMap         maOoxFuncs;         /// Maps OOXML function names to function data.
     987             :     FuncIdMap           maBiff12Funcs;      /// Maps BIFF12 function indexes to function data.
     988             :     FuncIdMap           maBiffFuncs;        /// Maps BIFF2-BIFF8 function indexes to function data.
     989             :     FuncNameMap         maMacroFuncs;       /// Maps macro function names to function data.
     990             : 
     991             :     explicit            FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter,
     992             :                                               bool bCallerKnowsAboutMacroExport );
     993             : 
     994             : private:
     995             :     /** Creates and inserts a function info struct from the passed function data. */
     996             :     void                initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam );
     997             : 
     998             :     /** Initializes the members from the passed function data list. */
     999             :     void                initFuncs(
    1000             :                             const FunctionData* pBeg, const FunctionData* pEnd,
    1001             :                             sal_uInt8 nMaxParam, bool bImportFilter, FilterType eFilter );
    1002             : };
    1003             : 
    1004         426 : FunctionProviderImpl::FunctionProviderImpl( FilterType eFilter, BiffType eBiff, bool bImportFilter,
    1005         426 :         bool bCallerKnowsAboutMacroExport )
    1006             : {
    1007             :     // NOTE: this warning is only applicable if called for not yet existing
    1008             :     // external export filter, not the Calc internal conversion from binary to
    1009             :     // OOXML that also uses this mapping. Which is the only reason for
    1010             :     // bCallerKnowsAboutMacroExport, to suppress this warning then.
    1011             :     OSL_ENSURE( bImportFilter || bCallerKnowsAboutMacroExport,
    1012             :             "FunctionProviderImpl::FunctionProviderImpl - need special handling for macro call functions" );
    1013             :     (void)bCallerKnowsAboutMacroExport;
    1014         426 :     sal_uInt8 nMaxParam = 0;
    1015         426 :     switch( eFilter )
    1016             :     {
    1017             :         case FILTER_OOXML:
    1018         426 :             nMaxParam = OOX_MAX_PARAMCOUNT;
    1019         426 :             eBiff = BIFF8;  // insert all BIFF function tables, then the OOXML table
    1020         426 :         break;
    1021             :         case FILTER_BIFF:
    1022           0 :             nMaxParam = BIFF_MAX_PARAMCOUNT;
    1023           0 :         break;
    1024             :         case FILTER_UNKNOWN:
    1025             :             OSL_FAIL( "FunctionProviderImpl::FunctionProviderImpl - invalid filter type" );
    1026           0 :         break;
    1027             :     }
    1028             :     OSL_ENSURE( eBiff != BIFF_UNKNOWN, "FunctionProviderImpl::FunctionProviderImpl - invalid BIFF type" );
    1029             : 
    1030             :     /*  Add functions supported in the current BIFF version only. Function
    1031             :         tables from later BIFF versions may overwrite single functions from
    1032             :         earlier tables. */
    1033         426 :     if( eBiff >= BIFF2 )
    1034         426 :         initFuncs( saFuncTableBiff2, STATIC_ARRAY_END( saFuncTableBiff2 ), nMaxParam, bImportFilter, eFilter );
    1035         426 :     if( eBiff >= BIFF3 )
    1036         426 :         initFuncs( saFuncTableBiff3, STATIC_ARRAY_END( saFuncTableBiff3 ), nMaxParam, bImportFilter, eFilter );
    1037         426 :     if( eBiff >= BIFF4 )
    1038         426 :         initFuncs( saFuncTableBiff4, STATIC_ARRAY_END( saFuncTableBiff4 ), nMaxParam, bImportFilter, eFilter );
    1039         426 :     if( eBiff >= BIFF5 )
    1040         426 :         initFuncs( saFuncTableBiff5, STATIC_ARRAY_END( saFuncTableBiff5 ), nMaxParam, bImportFilter, eFilter );
    1041         426 :     if( eBiff >= BIFF8 )
    1042         426 :         initFuncs( saFuncTableBiff8, STATIC_ARRAY_END( saFuncTableBiff8 ), nMaxParam, bImportFilter, eFilter );
    1043         426 :     initFuncs( saFuncTableOox, STATIC_ARRAY_END( saFuncTableOox ), nMaxParam, bImportFilter, eFilter );
    1044         426 :     initFuncs( saFuncTable2010, STATIC_ARRAY_END( saFuncTable2010 ), nMaxParam, bImportFilter, eFilter );
    1045         426 :     initFuncs( saFuncTable2013, STATIC_ARRAY_END( saFuncTable2013 ), nMaxParam, bImportFilter, eFilter );
    1046         426 :     initFuncs( saFuncTableOdf, STATIC_ARRAY_END( saFuncTableOdf ), nMaxParam, bImportFilter, eFilter );
    1047         426 :     initFuncs( saFuncTableOOoLO, STATIC_ARRAY_END( saFuncTableOOoLO ), nMaxParam, bImportFilter, eFilter );
    1048         426 : }
    1049             : 
    1050      224860 : void FunctionProviderImpl::initFunc( const FunctionData& rFuncData, sal_uInt8 nMaxParam )
    1051             : {
    1052             :     // create a function info object
    1053      224860 :     FunctionInfoRef xFuncInfo( new FunctionInfo );
    1054      224860 :     if( rFuncData.mpcOdfFuncName )
    1055      202822 :         xFuncInfo->maOdfFuncName = OUString::createFromAscii( rFuncData.mpcOdfFuncName );
    1056      224860 :     if( rFuncData.mpcOoxFuncName )
    1057      224008 :         xFuncInfo->maOoxFuncName = OUString::createFromAscii( rFuncData.mpcOoxFuncName );
    1058             : 
    1059      224860 :     if( getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALL ) )
    1060             :     {
    1061             :         OSL_ENSURE( !xFuncInfo->maOoxFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing OOXML function name" );
    1062             :         OSL_ENSURE( !getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALLODF ), "FunctionProviderImpl::initFunc - unexpected flag FUNCFLAG_MACROCALLODF" );
    1063       59214 :         xFuncInfo->maBiffMacroName = "_xlfn." + xFuncInfo->maOoxFuncName;
    1064       59214 :         if( getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALL_FN ) )
    1065             :         {
    1066       51120 :             xFuncInfo->maOoxFuncName = "_xlfn." + xFuncInfo->maOoxFuncName;
    1067             :             //! From here on maOoxFuncName contains the _xlfn. prefix!
    1068             :         }
    1069             :     }
    1070      165646 :     else if( getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCALLODF ) )
    1071             :     {
    1072             :         OSL_ENSURE( !xFuncInfo->maOdfFuncName.isEmpty(), "FunctionProviderImpl::initFunc - missing ODF function name" );
    1073         852 :         xFuncInfo->maBiffMacroName = "_xlfnodf." + xFuncInfo->maOdfFuncName;
    1074             :     }
    1075             : 
    1076      224860 :     xFuncInfo->meFuncLibType = FUNCFLAGS_TO_FUNCLIB( rFuncData.mnFlags );
    1077      224860 :     xFuncInfo->mnApiOpCode = -1;
    1078      224860 :     xFuncInfo->mnBiff12FuncId = rFuncData.mnBiff12FuncId;
    1079      224860 :     xFuncInfo->mnBiffFuncId = rFuncData.mnBiffFuncId;
    1080      224860 :     xFuncInfo->mnMinParamCount = rFuncData.mnMinParamCount;
    1081      224860 :     xFuncInfo->mnMaxParamCount = (rFuncData.mnMaxParamCount == MX) ? nMaxParam : rFuncData.mnMaxParamCount;
    1082      224860 :     xFuncInfo->mnRetClass = rFuncData.mnRetClass;
    1083      224860 :     xFuncInfo->mpParamInfos = rFuncData.mpParamInfos;
    1084      224860 :     xFuncInfo->mbParamPairs = getFlag( rFuncData.mnFlags, FUNCFLAG_PARAMPAIRS );
    1085      224860 :     xFuncInfo->mbVolatile = getFlag( rFuncData.mnFlags, FUNCFLAG_VOLATILE );
    1086      224860 :     xFuncInfo->mbExternal = getFlag( rFuncData.mnFlags, FUNCFLAG_EXTERNAL );
    1087      224860 :     xFuncInfo->mbInternal = !xFuncInfo->mbExternal || getFlag( rFuncData.mnFlags, FUNCFLAG_INTERNAL );
    1088      224860 :     bool bMacroCmd = getFlag( rFuncData.mnFlags, FUNCFLAG_MACROCMD );
    1089      224860 :     xFuncInfo->mbMacroFunc = bMacroCmd || getFlag( rFuncData.mnFlags, FUNCFLAG_MACROFUNC );
    1090      224860 :     xFuncInfo->mbVarParam = bMacroCmd || (rFuncData.mnMinParamCount != rFuncData.mnMaxParamCount) || getFlag( rFuncData.mnFlags, FUNCFLAG_ALWAYSVAR );
    1091             : 
    1092      224860 :     setFlag( xFuncInfo->mnBiff12FuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
    1093      224860 :     setFlag( xFuncInfo->mnBiffFuncId, BIFF_TOK_FUNCVAR_CMD, bMacroCmd );
    1094             : 
    1095             :     // insert the function info into the member maps
    1096      224860 :     maFuncs.push_back( xFuncInfo );
    1097      224860 :     if( !xFuncInfo->maOoxFuncName.isEmpty() )
    1098      224008 :         maOoxFuncs[ xFuncInfo->maOoxFuncName ] = xFuncInfo;
    1099      224860 :     if( xFuncInfo->mnBiff12FuncId != NOID )
    1100      224860 :         maBiff12Funcs[ xFuncInfo->mnBiff12FuncId ] = xFuncInfo;
    1101      224860 :     if( xFuncInfo->mnBiffFuncId != NOID )
    1102      224860 :         maBiffFuncs[ xFuncInfo->mnBiffFuncId ] = xFuncInfo;
    1103      224860 :     if( !xFuncInfo->maBiffMacroName.isEmpty() )
    1104       60066 :         maMacroFuncs[ xFuncInfo->maBiffMacroName ] = xFuncInfo;
    1105      224860 : }
    1106             : 
    1107        4260 : void FunctionProviderImpl::initFuncs( const FunctionData* pBeg, const FunctionData* pEnd, sal_uInt8 nMaxParam,
    1108             :         bool bImportFilter, FilterType eFilter )
    1109             : {
    1110      233874 :     for( const FunctionData* pIt = pBeg; pIt != pEnd; ++pIt )
    1111      229614 :         if( pIt->isSupported( bImportFilter, eFilter ) )
    1112      224860 :             initFunc( *pIt, nMaxParam );
    1113        4260 : }
    1114             : 
    1115         426 : FunctionProvider::FunctionProvider( FilterType eFilter, BiffType eBiff, bool bImportFilter,
    1116             :         bool bCallerKnowsAboutMacroExport ) :
    1117         426 :     mxFuncImpl( new FunctionProviderImpl( eFilter, eBiff, bImportFilter, bCallerKnowsAboutMacroExport ) )
    1118             : {
    1119         426 : }
    1120             : 
    1121        1202 : FunctionProvider::~FunctionProvider()
    1122             : {
    1123        1202 : }
    1124             : 
    1125           0 : const FunctionInfo* FunctionProvider::getFuncInfoFromOoxFuncName( const OUString& rFuncName ) const
    1126             : {
    1127           0 :     return mxFuncImpl->maOoxFuncs.get( rFuncName ).get();
    1128             : }
    1129             : 
    1130           0 : const FunctionInfo* FunctionProvider::getFuncInfoFromBiff12FuncId( sal_uInt16 nFuncId ) const
    1131             : {
    1132           0 :     return mxFuncImpl->maBiff12Funcs.get( nFuncId ).get();
    1133             : }
    1134             : 
    1135           0 : const FunctionInfo* FunctionProvider::getFuncInfoFromBiffFuncId( sal_uInt16 nFuncId ) const
    1136             : {
    1137           0 :     return mxFuncImpl->maBiffFuncs.get( nFuncId ).get();
    1138             : }
    1139             : 
    1140           0 : const FunctionInfo* FunctionProvider::getFuncInfoFromMacroName( const OUString& rFuncName ) const
    1141             : {
    1142           0 :     return mxFuncImpl->maMacroFuncs.get( rFuncName ).get();
    1143             : }
    1144             : 
    1145           0 : FunctionLibraryType FunctionProvider::getFuncLibTypeFromLibraryName( const OUString& rLibraryName ) const
    1146             : {
    1147             : #define OOX_XLS_IS_LIBNAME( libname, basename ) (libname.equalsIgnoreAsciiCase( basename ".XLA" ) || libname.equalsIgnoreAsciiCase( basename ".XLAM" ))
    1148             : 
    1149             :     // the EUROTOOL add-in containing the EUROCONVERT function
    1150           0 :     if( OOX_XLS_IS_LIBNAME( rLibraryName, "EUROTOOL" ) )
    1151           0 :         return FUNCLIB_EUROTOOL;
    1152             : 
    1153             : #undef OOX_XLS_IS_LIBNAME
    1154             : 
    1155             :     // default: unknown library
    1156           0 :     return FUNCLIB_UNKNOWN;
    1157             : }
    1158             : 
    1159         426 : const FunctionInfoVector& FunctionProvider::getFuncs() const
    1160             : {
    1161         426 :     return mxFuncImpl->maFuncs;
    1162             : }
    1163             : 
    1164             : // op-code and function provider ==============================================
    1165             : 
    1166         426 : struct OpCodeProviderImpl : public ApiOpCodes
    1167             : {
    1168             :     typedef RefMap< sal_Int32, FunctionInfo >       OpCodeFuncMap;
    1169             :     typedef RefMap< OUString, FunctionInfo >        FuncNameMap;
    1170             :     typedef ::std::vector< FormulaOpCodeMapEntry >  OpCodeEntryVector;
    1171             : 
    1172             :     OpCodeFuncMap       maOpCodeFuncs;      /// Maps API function op-codes to function data.
    1173             :     FuncNameMap         maExtProgFuncs;     /// Maps programmatical API function names to function data.
    1174             :     OpCodeEntryVector   maParserMap;        /// OOXML token mapping for formula parser service.
    1175             : 
    1176             :     explicit            OpCodeProviderImpl(
    1177             :                             const FunctionInfoVector& rFuncInfos,
    1178             :                             const Reference< XMultiServiceFactory >& rxModelFactory );
    1179             : 
    1180             : private:
    1181             :     typedef ::std::map< OUString, ApiToken >    ApiTokenMap;
    1182             :     typedef Sequence< FormulaOpCodeMapEntry >   OpCodeEntrySequence;
    1183             : 
    1184             :     static bool         fillEntrySeq( OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
    1185             :     static bool         fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup );
    1186             :     bool                fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const;
    1187             : 
    1188             :     static bool         initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId );
    1189             :     bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName );
    1190             :     bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName );
    1191             :     bool                initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName );
    1192             : 
    1193             :     bool                initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap );
    1194             :     bool                initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos );
    1195             : };
    1196             : 
    1197         426 : OpCodeProviderImpl::OpCodeProviderImpl( const FunctionInfoVector& rFuncInfos,
    1198         426 :         const Reference< XMultiServiceFactory >& rxModelFactory )
    1199             : {
    1200         426 :     if( rxModelFactory.is() ) try
    1201             :     {
    1202         426 :         Reference< XFormulaOpCodeMapper > xMapper( rxModelFactory->createInstance(
    1203         426 :             "com.sun.star.sheet.FormulaOpCodeMapper" ), UNO_QUERY_THROW );
    1204             : 
    1205             :         // op-codes provided as attributes
    1206         426 :         OPCODE_UNKNOWN = xMapper->getOpCodeUnknown();
    1207         426 :         OPCODE_EXTERNAL = xMapper->getOpCodeExternal();
    1208             : 
    1209             :         using namespace ::com::sun::star::sheet::FormulaMapGroup;
    1210             :         using namespace ::com::sun::star::sheet::FormulaMapGroupSpecialOffset;
    1211             : 
    1212         852 :         OpCodeEntrySequence aEntrySeq;
    1213         852 :         ApiTokenMap aTokenMap, aExtFuncTokenMap;
    1214             :         bool bIsValid =
    1215             :             // special
    1216         852 :             fillEntrySeq( aEntrySeq, xMapper, SPECIAL ) &&
    1217         852 :             initOpCode( OPCODE_PUSH,          aEntrySeq, PUSH ) &&
    1218         852 :             initOpCode( OPCODE_MISSING,       aEntrySeq, MISSING ) &&
    1219         852 :             initOpCode( OPCODE_SPACES,        aEntrySeq, SPACES ) &&
    1220         852 :             initOpCode( OPCODE_NAME,          aEntrySeq, NAME ) &&
    1221         852 :             initOpCode( OPCODE_DBAREA,        aEntrySeq, DB_AREA ) &&
    1222         852 :             initOpCode( OPCODE_NLR,           aEntrySeq, COL_ROW_NAME ) &&
    1223         852 :             initOpCode( OPCODE_MACRO,         aEntrySeq, MACRO ) &&
    1224         852 :             initOpCode( OPCODE_BAD,           aEntrySeq, BAD ) &&
    1225         852 :             initOpCode( OPCODE_NONAME,        aEntrySeq, NO_NAME ) &&
    1226             :             // separators
    1227         852 :             fillTokenMap( aTokenMap, aEntrySeq, xMapper, SEPARATORS ) &&
    1228         852 :             initOpCode( OPCODE_OPEN,          aTokenMap, API_TOKEN_OPEN,  '('  ) &&
    1229         852 :             initOpCode( OPCODE_CLOSE,         aTokenMap, API_TOKEN_CLOSE, ')'  ) &&
    1230         852 :             initOpCode( OPCODE_SEP,           aTokenMap, API_TOKEN_SEP,   ','  ) &&
    1231             :             // array separators
    1232         852 :             fillTokenMap( aTokenMap, aEntrySeq, xMapper, ARRAY_SEPARATORS ) &&
    1233         852 :             initOpCode( OPCODE_ARRAY_OPEN,    aTokenMap, API_TOKEN_ARRAY_OPEN,   '{'  ) &&
    1234         852 :             initOpCode( OPCODE_ARRAY_CLOSE,   aTokenMap, API_TOKEN_ARRAY_CLOSE,  '}'  ) &&
    1235         852 :             initOpCode( OPCODE_ARRAY_ROWSEP,  aTokenMap, API_TOKEN_ARRAY_ROWSEP, ';'  ) &&
    1236         852 :             initOpCode( OPCODE_ARRAY_COLSEP,  aTokenMap, API_TOKEN_ARRAY_COLSEP, ','  ) &&
    1237             :             // unary operators
    1238         852 :             fillTokenMap( aTokenMap, aEntrySeq, xMapper, UNARY_OPERATORS ) &&
    1239         852 :             initOpCode( OPCODE_PLUS_SIGN,     aTokenMap, '+',  '\0' ) && // same op-code as OPCODE_ADD
    1240         852 :             initOpCode( OPCODE_MINUS_SIGN,    aTokenMap, '-',  '-'  ) &&
    1241         852 :             initOpCode( OPCODE_PERCENT,       aTokenMap, '%',  '%'  ) &&
    1242             :             // binary operators
    1243         852 :             fillTokenMap( aTokenMap, aEntrySeq, xMapper, BINARY_OPERATORS ) &&
    1244         852 :             initOpCode( OPCODE_ADD,           aTokenMap, '+',  '+'  ) &&
    1245         852 :             initOpCode( OPCODE_SUB,           aTokenMap, '-',  '-'  ) &&
    1246         852 :             initOpCode( OPCODE_MULT,          aTokenMap, '*',  '*'  ) &&
    1247         852 :             initOpCode( OPCODE_DIV,           aTokenMap, '/',  '/'  ) &&
    1248         852 :             initOpCode( OPCODE_POWER,         aTokenMap, '^',  '^'  ) &&
    1249         852 :             initOpCode( OPCODE_CONCAT,        aTokenMap, '&',  '&'  ) &&
    1250         852 :             initOpCode( OPCODE_EQUAL,         aTokenMap, '=',  '='  ) &&
    1251         852 :             initOpCode( OPCODE_NOT_EQUAL,     aTokenMap, "<>", "<>" ) &&
    1252         852 :             initOpCode( OPCODE_LESS,          aTokenMap, '<',  '<'  ) &&
    1253         852 :             initOpCode( OPCODE_LESS_EQUAL,    aTokenMap, "<=", "<=" ) &&
    1254         852 :             initOpCode( OPCODE_GREATER,       aTokenMap, '>',  '>'  ) &&
    1255         852 :             initOpCode( OPCODE_GREATER_EQUAL, aTokenMap, ">=", ">=" ) &&
    1256         852 :             initOpCode( OPCODE_INTERSECT,     aTokenMap, '!',  ' '  ) &&
    1257         852 :             initOpCode( OPCODE_LIST,          aTokenMap, '~',  ','  ) &&
    1258         852 :             initOpCode( OPCODE_RANGE,         aTokenMap, ':',  ':'  ) &&
    1259             :             // functions
    1260         852 :             fillFuncTokenMaps( aTokenMap, aExtFuncTokenMap, aEntrySeq, xMapper ) &&
    1261        1278 :             initFuncOpCodes( aTokenMap, aExtFuncTokenMap, rFuncInfos ) &&
    1262         852 :             initOpCode( OPCODE_DDE,           aTokenMap, "DDE", 0 );
    1263             : 
    1264             :         OSL_ENSURE( bIsValid, "OpCodeProviderImpl::OpCodeProviderImpl - opcodes not initialized" );
    1265             :         (void)bIsValid;
    1266             : 
    1267             :         // OPCODE_PLUS_SIGN and OPCODE_ADD should be equal, otherwise "+" has to be passed above
    1268         426 :         OSL_ENSURE( OPCODE_PLUS_SIGN == OPCODE_ADD, "OpCodeProviderImpl::OpCodeProviderImpl - need opcode mapping for OPCODE_PLUS_SIGN" );
    1269             :     }
    1270           0 :     catch( Exception& )
    1271             :     {
    1272             :         OSL_FAIL( "OpCodeProviderImpl::OpCodeProviderImpl - cannot receive formula opcode mapper" );
    1273             :     }
    1274         426 : }
    1275             : 
    1276        2556 : bool OpCodeProviderImpl::fillEntrySeq( OpCodeEntrySequence& orEntrySeq,
    1277             :         const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
    1278             : {
    1279             :     try
    1280             :     {
    1281        2556 :         orEntrySeq = rxMapper->getAvailableMappings( ::com::sun::star::sheet::FormulaLanguage::ODFF, nMapGroup );
    1282        2556 :         return orEntrySeq.hasElements();
    1283             :     }
    1284           0 :     catch( Exception& )
    1285             :     {
    1286             :     }
    1287           0 :     return false;
    1288             : }
    1289             : 
    1290        1704 : bool OpCodeProviderImpl::fillTokenMap( ApiTokenMap& orTokenMap, OpCodeEntrySequence& orEntrySeq,
    1291             :         const Reference< XFormulaOpCodeMapper >& rxMapper, sal_Int32 nMapGroup )
    1292             : {
    1293        1704 :     orTokenMap.clear();
    1294        1704 :     if( fillEntrySeq( orEntrySeq, rxMapper, nMapGroup ) )
    1295             :     {
    1296        1704 :         const FormulaOpCodeMapEntry* pEntry = orEntrySeq.getConstArray();
    1297        1704 :         const FormulaOpCodeMapEntry* pEntryEnd = pEntry + orEntrySeq.getLength();
    1298       12354 :         for( ; pEntry != pEntryEnd; ++pEntry )
    1299       10650 :             orTokenMap[ pEntry->Name ] = pEntry->Token;
    1300             :     }
    1301        1704 :     return orEntrySeq.hasElements();
    1302             : }
    1303             : 
    1304         426 : bool OpCodeProviderImpl::fillFuncTokenMaps( ApiTokenMap& orIntFuncTokenMap, ApiTokenMap& orExtFuncTokenMap, OpCodeEntrySequence& orEntrySeq, const Reference< XFormulaOpCodeMapper >& rxMapper ) const
    1305             : {
    1306         426 :     orIntFuncTokenMap.clear();
    1307         426 :     orExtFuncTokenMap.clear();
    1308         426 :     if( fillEntrySeq( orEntrySeq, rxMapper, ::com::sun::star::sheet::FormulaMapGroup::FUNCTIONS ) )
    1309             :     {
    1310         426 :         const FormulaOpCodeMapEntry* pEntry = orEntrySeq.getConstArray();
    1311         426 :         const FormulaOpCodeMapEntry* pEntryEnd = pEntry + orEntrySeq.getLength();
    1312      204906 :         for( ; pEntry != pEntryEnd; ++pEntry )
    1313      204480 :             ((pEntry->Token.OpCode == OPCODE_EXTERNAL) ? orExtFuncTokenMap : orIntFuncTokenMap)[ pEntry->Name ] = pEntry->Token;
    1314             :     }
    1315         426 :     return orEntrySeq.hasElements();
    1316             : }
    1317             : 
    1318        3834 : bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const OpCodeEntrySequence& rEntrySeq, sal_Int32 nSpecialId )
    1319             : {
    1320        3834 :     if( (0 <= nSpecialId) && (nSpecialId < rEntrySeq.getLength()) )
    1321             :     {
    1322        3834 :         ornOpCode = rEntrySeq[ nSpecialId ].Token.OpCode;
    1323        3834 :         return true;
    1324             :     }
    1325             :     OSL_FAIL( OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for special offset " ).
    1326             :         append( nSpecialId ).append( " not found" ).getStr() );
    1327           0 :     return false;
    1328             : }
    1329             : 
    1330       11076 : bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const OUString& rOdfName, const OUString& rOoxName )
    1331             : {
    1332       11076 :     ApiTokenMap::const_iterator aIt = rTokenMap.find( rOdfName );
    1333       11076 :     if( aIt != rTokenMap.end() )
    1334             :     {
    1335       11076 :         ornOpCode = aIt->second.OpCode;
    1336       11076 :         if( !rOoxName.isEmpty() )
    1337             :         {
    1338       10224 :             FormulaOpCodeMapEntry aEntry;
    1339       10224 :             aEntry.Name = rOoxName;
    1340       10224 :             aEntry.Token.OpCode = ornOpCode;
    1341       10224 :             maParserMap.push_back( aEntry );
    1342             :         }
    1343       11076 :         return true;
    1344             :     }
    1345             :     OSL_FAIL( OStringBuffer( "OpCodeProviderImpl::initOpCode - opcode for \"" ).
    1346             :         append( OUStringToOString( rOdfName, RTL_TEXTENCODING_ASCII_US ) ).
    1347             :         append( "\" not found" ).getStr() );
    1348           0 :     return false;
    1349             : }
    1350             : 
    1351        1704 : bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, const sal_Char* pcOdfName, const sal_Char* pcOoxName )
    1352             : {
    1353        1704 :     OUString aOoxName;
    1354        1704 :     if( pcOoxName ) aOoxName = OUString::createFromAscii( pcOoxName );
    1355        1704 :     return initOpCode( ornOpCode, rTokenMap, OUString::createFromAscii( pcOdfName ), aOoxName );
    1356             : }
    1357             : 
    1358        9372 : bool OpCodeProviderImpl::initOpCode( sal_Int32& ornOpCode, const ApiTokenMap& rTokenMap, sal_Unicode cOdfName, sal_Unicode cOoxName )
    1359             : {
    1360        9372 :     OUString aOoxName;
    1361        9372 :     if( cOoxName ) aOoxName = OUString( cOoxName );
    1362        9372 :     return initOpCode( ornOpCode, rTokenMap, OUString( cOdfName ), aOoxName );
    1363             : }
    1364             : 
    1365      228268 : bool OpCodeProviderImpl::initFuncOpCode( FunctionInfo& orFuncInfo, const ApiTokenMap& rFuncTokenMap )
    1366             : {
    1367      228268 :     bool bIsValid = false;
    1368      228268 :     if( !orFuncInfo.maOdfFuncName.isEmpty() )
    1369             :     {
    1370      206230 :         ApiTokenMap::const_iterator aIt = rFuncTokenMap.find( orFuncInfo.maOdfFuncName );
    1371      206230 :         if( aIt != rFuncTokenMap.end() )
    1372             :         {
    1373      206230 :             orFuncInfo.mnApiOpCode = aIt->second.OpCode;
    1374             :             bIsValid =
    1375      412460 :                 (orFuncInfo.mnApiOpCode >= 0) &&
    1376      412460 :                 (orFuncInfo.mnApiOpCode != OPCODE_UNKNOWN) &&
    1377      412460 :                 (orFuncInfo.mnApiOpCode != OPCODE_NONAME);
    1378             :             OSL_ENSURE( bIsValid,
    1379             :                 OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no valid opcode for ODF function \"" ).
    1380             :                 append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
    1381             :                 append( '"' ).getStr() );
    1382             : 
    1383      206230 :             if( bIsValid && (orFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) )
    1384             :             {
    1385       49538 :                 bIsValid = (aIt->second.Data >>= orFuncInfo.maExtProgName) && !orFuncInfo.maExtProgName.isEmpty();
    1386             :                 OSL_ENSURE( bIsValid,
    1387             :                     OStringBuffer( "OpCodeProviderImpl::initFuncOpCode - no programmatical name for external function \"" ).
    1388             :                     append( OUStringToOString( orFuncInfo.maOdfFuncName, RTL_TEXTENCODING_ASCII_US ) ).
    1389             :                     append( '"' ).getStr() );
    1390             :             }
    1391             : 
    1392             :             // add to parser map, if OOXML function name exists
    1393      206230 :             if( bIsValid && !orFuncInfo.maOoxFuncName.isEmpty() )
    1394             :             {
    1395             :                 // create the parser map entry
    1396      205378 :                 FormulaOpCodeMapEntry aEntry;
    1397      205378 :                 aEntry.Name = orFuncInfo.maOoxFuncName;
    1398      205378 :                 aEntry.Token = aIt->second;
    1399      205378 :                 maParserMap.push_back( aEntry );
    1400             :             }
    1401             :         }
    1402             :         else
    1403             :         {
    1404             :             // ignore entries for functions unknown by Calc *and* by Excel
    1405           0 :             bIsValid = orFuncInfo.maOoxFuncName.isEmpty();
    1406             :             SAL_WARN_IF( !bIsValid, "sc",
    1407             :                     "OpCodeProviderImpl::initFuncOpCode - no opcode mapping for function ODF '" <<
    1408             :                     orFuncInfo.maOdfFuncName << "' <-> OOXML '" << orFuncInfo.maOoxFuncName << "'");
    1409             :         }
    1410             :     }
    1411       22038 :     else if( orFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
    1412             :     {
    1413         426 :         orFuncInfo.mnApiOpCode = OPCODE_EXTERNAL;
    1414         426 :         bIsValid = true;
    1415             :     }
    1416       21612 :     else if( !orFuncInfo.maOoxFuncName.isEmpty() )
    1417             :     {
    1418       21612 :         orFuncInfo.mnApiOpCode = OPCODE_BAD;
    1419       21612 :         bIsValid = true;
    1420             :     }
    1421             : 
    1422      228268 :     if( !bIsValid || (orFuncInfo.mnApiOpCode == OPCODE_UNKNOWN) || (orFuncInfo.mnApiOpCode < 0) )
    1423           0 :         orFuncInfo.mnApiOpCode = OPCODE_NONAME;
    1424      228268 :     return bIsValid;
    1425             : }
    1426             : 
    1427         426 : bool OpCodeProviderImpl::initFuncOpCodes( const ApiTokenMap& rIntFuncTokenMap, const ApiTokenMap& rExtFuncTokenMap, const FunctionInfoVector& rFuncInfos )
    1428             : {
    1429         426 :     bool bIsValid = true;
    1430      225286 :     for( FunctionInfoVector::const_iterator aIt = rFuncInfos.begin(), aEnd = rFuncInfos.end(); aIt != aEnd; ++aIt )
    1431             :     {
    1432      224860 :         FunctionInfoRef xFuncInfo = *aIt;
    1433             :         // set API opcode from ODF function name
    1434      224860 :         if (xFuncInfo->mbExternal)
    1435       49538 :             bIsValid &= initFuncOpCode( *xFuncInfo, rExtFuncTokenMap );
    1436      224860 :         if (xFuncInfo->mbInternal)
    1437      178730 :             bIsValid &= initFuncOpCode( *xFuncInfo, rIntFuncTokenMap );
    1438             :         // insert the function info into the maps
    1439      224860 :         if( (xFuncInfo->mnApiOpCode != OPCODE_NONAME) && (xFuncInfo->mnApiOpCode != OPCODE_BAD) )
    1440             :         {
    1441      203248 :             if( (xFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && !xFuncInfo->maExtProgName.isEmpty() )
    1442       46130 :                 maExtProgFuncs[ xFuncInfo->maExtProgName ] = xFuncInfo;
    1443             :             else
    1444      157118 :                 maOpCodeFuncs[ xFuncInfo->mnApiOpCode ] = xFuncInfo;
    1445             :         }
    1446      224860 :     }
    1447         426 :     return bIsValid;
    1448             : }
    1449             : 
    1450         426 : OpCodeProvider::OpCodeProvider( const Reference< XMultiServiceFactory >& rxModelFactory,
    1451             :         FilterType eFilter, BiffType eBiff, bool bImportFilter, bool bCallerKnowsAboutMacroExport ) :
    1452             :     FunctionProvider( eFilter, eBiff, bImportFilter, bCallerKnowsAboutMacroExport ),
    1453         426 :     mxOpCodeImpl( new OpCodeProviderImpl( getFuncs(), rxModelFactory ) )
    1454             : {
    1455         426 : }
    1456             : 
    1457        1202 : OpCodeProvider::~OpCodeProvider()
    1458             : {
    1459        1202 : }
    1460             : 
    1461         776 : const ApiOpCodes& OpCodeProvider::getOpCodes() const
    1462             : {
    1463         776 :     return *mxOpCodeImpl;
    1464             : }
    1465             : 
    1466         172 : const FunctionInfo* OpCodeProvider::getFuncInfoFromApiToken( const ApiToken& rToken ) const
    1467             : {
    1468         172 :     const FunctionInfo* pFuncInfo = 0;
    1469         172 :     if( (rToken.OpCode == mxOpCodeImpl->OPCODE_EXTERNAL) && rToken.Data.has< OUString >() )
    1470           0 :         pFuncInfo = mxOpCodeImpl->maExtProgFuncs.get( rToken.Data.get< OUString >() ).get();
    1471         172 :     else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_MACRO) && rToken.Data.has< OUString >() )
    1472           0 :         pFuncInfo = getFuncInfoFromMacroName( rToken.Data.get< OUString >() );
    1473         172 :     else if( (rToken.OpCode == mxOpCodeImpl->OPCODE_BAD) && rToken.Data.has< OUString >() )
    1474           0 :         pFuncInfo = getFuncInfoFromOoxFuncName( rToken.Data.get< OUString >() );
    1475             :     else
    1476         172 :         pFuncInfo = mxOpCodeImpl->maOpCodeFuncs.get( rToken.OpCode ).get();
    1477         172 :     return pFuncInfo;
    1478             : }
    1479             : 
    1480         426 : Sequence< FormulaOpCodeMapEntry > OpCodeProvider::getOoxParserMap() const
    1481             : {
    1482         426 :     return ContainerHelper::vectorToSequence( mxOpCodeImpl->maParserMap );
    1483             : }
    1484             : 
    1485             : // API formula parser wrapper =================================================
    1486             : 
    1487         388 : ApiParserWrapper::ApiParserWrapper(
    1488             :         const Reference< XMultiServiceFactory >& rxModelFactory, const OpCodeProvider& rOpCodeProv ) :
    1489         388 :     OpCodeProvider( rOpCodeProv )
    1490             : {
    1491         388 :     if( rxModelFactory.is() ) try
    1492             :     {
    1493         388 :         mxParser.set( rxModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), UNO_QUERY_THROW );
    1494             :     }
    1495           0 :     catch( Exception& )
    1496             :     {
    1497             :     }
    1498             :     OSL_ENSURE( mxParser.is(), "ApiParserWrapper::ApiParserWrapper - cannot create API formula parser object" );
    1499         388 :     maParserProps.set( mxParser );
    1500         388 :     maParserProps.setProperty( PROP_CompileEnglish, true );
    1501         388 :     maParserProps.setProperty( PROP_FormulaConvention, ::com::sun::star::sheet::AddressConvention::XL_OOX );
    1502         388 :     maParserProps.setProperty( PROP_IgnoreLeadingSpaces, false );
    1503         388 :     maParserProps.setProperty( PROP_OpCodeMap, getOoxParserMap() );
    1504         388 : }
    1505             : 
    1506         148 : ApiTokenSequence ApiParserWrapper::parseFormula( const OUString& rFormula, const CellAddress& rRefPos )
    1507             : {
    1508         148 :     ApiTokenSequence aTokenSeq;
    1509         148 :     if( mxParser.is() ) try
    1510             :     {
    1511         148 :         aTokenSeq = mxParser->parseFormula( rFormula, rRefPos );
    1512             :     }
    1513           0 :     catch( Exception& )
    1514             :     {
    1515             :     }
    1516         148 :     return aTokenSeq;
    1517             : }
    1518             : 
    1519             : // formula parser/printer base class for filters ==============================
    1520             : 
    1521             : namespace {
    1522             : 
    1523           0 : bool lclConvertToCellAddress( CellAddress& orAddress, const SingleReference& rSingleRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
    1524             : {
    1525             :     orAddress = CellAddress( static_cast< sal_Int16 >( rSingleRef.Sheet ),
    1526           0 :         rSingleRef.Column, rSingleRef.Row );
    1527             :     return
    1528           0 :         !getFlag( rSingleRef.Flags, nForbiddenFlags ) &&
    1529           0 :         ((nFilterBySheet < 0) || (nFilterBySheet == rSingleRef.Sheet));
    1530             : }
    1531             : 
    1532           2 : bool lclConvertToCellRange( CellRangeAddress& orRange, const ComplexReference& rComplexRef, sal_Int32 nForbiddenFlags, sal_Int32 nFilterBySheet )
    1533             : {
    1534             :     orRange = CellRangeAddress( static_cast< sal_Int16 >( rComplexRef.Reference1.Sheet ),
    1535             :         rComplexRef.Reference1.Column, rComplexRef.Reference1.Row,
    1536           2 :         rComplexRef.Reference2.Column, rComplexRef.Reference2.Row );
    1537             :     return
    1538           4 :         !getFlag( rComplexRef.Reference1.Flags, nForbiddenFlags ) &&
    1539           4 :         !getFlag( rComplexRef.Reference2.Flags, nForbiddenFlags ) &&
    1540           8 :         (rComplexRef.Reference1.Sheet == rComplexRef.Reference2.Sheet) &&
    1541           2 :         ((nFilterBySheet < 0) || (nFilterBySheet == rComplexRef.Reference1.Sheet));
    1542             : }
    1543             : 
    1544             : enum TokenToRangeListState { STATE_REF, STATE_SEP, STATE_OPEN, STATE_CLOSE, STATE_ERROR };
    1545             : 
    1546           2 : TokenToRangeListState lclProcessRef( ApiCellRangeList& orRanges, const Any& rData, bool bAllowRelative, sal_Int32 nFilterBySheet )
    1547             : {
    1548             :     using namespace ::com::sun::star::sheet::ReferenceFlags;
    1549           2 :     const sal_Int32 FORBIDDEN_FLAGS_DEL = COLUMN_DELETED | ROW_DELETED | SHEET_DELETED;
    1550           2 :     const sal_Int32 FORBIDDEN_FLAGS_REL = FORBIDDEN_FLAGS_DEL | COLUMN_RELATIVE | ROW_RELATIVE | SHEET_RELATIVE | RELATIVE_NAME;
    1551             : 
    1552           2 :     sal_Int32 nForbiddenFlags = bAllowRelative ? FORBIDDEN_FLAGS_DEL : FORBIDDEN_FLAGS_REL;
    1553           2 :     SingleReference aSingleRef;
    1554           2 :     if( rData >>= aSingleRef )
    1555             :     {
    1556           0 :         CellAddress aAddress;
    1557             :         // ignore invalid addresses (with #REF! errors), but do not stop parsing
    1558           0 :         if( lclConvertToCellAddress( aAddress, aSingleRef, nForbiddenFlags, nFilterBySheet ) )
    1559           0 :             orRanges.push_back( CellRangeAddress( aAddress.Sheet, aAddress.Column, aAddress.Row, aAddress.Column, aAddress.Row ) );
    1560           0 :         return STATE_REF;
    1561             :     }
    1562           2 :     ComplexReference aComplexRef;
    1563           2 :     if( rData >>= aComplexRef )
    1564             :     {
    1565           2 :         CellRangeAddress aRange;
    1566             :         // ignore invalid ranges (with #REF! errors), but do not stop parsing
    1567           2 :         if( lclConvertToCellRange( aRange, aComplexRef, nForbiddenFlags, nFilterBySheet ) )
    1568           2 :             orRanges.push_back( aRange );
    1569           2 :         return STATE_REF;
    1570             :     }
    1571           0 :     return STATE_ERROR;
    1572             : }
    1573             : 
    1574           0 : TokenToRangeListState lclProcessOpen( sal_Int32& ornParenLevel )
    1575             : {
    1576           0 :     ++ornParenLevel;
    1577           0 :     return STATE_OPEN;
    1578             : }
    1579             : 
    1580           0 : TokenToRangeListState lclProcessClose( sal_Int32& ornParenLevel )
    1581             : {
    1582           0 :     --ornParenLevel;
    1583           0 :     return (ornParenLevel >= 0) ? STATE_CLOSE : STATE_ERROR;
    1584             : }
    1585             : 
    1586             : } // namespace
    1587             : 
    1588         388 : FormulaProcessorBase::FormulaProcessorBase( const WorkbookHelper& rHelper ) :
    1589         776 :     OpCodeProvider( rHelper.getBaseFilter().getModelFactory(), rHelper.getFilterType(), rHelper.getBiff(), rHelper.getBaseFilter().isImportFilter() ),
    1590         388 :     ApiOpCodes( getOpCodes() ),
    1591        1164 :     WorkbookHelper( rHelper )
    1592             : {
    1593         388 : }
    1594             : 
    1595           0 : OUString FormulaProcessorBase::generateAddress2dString( const CellAddress& rAddress, bool bAbsolute )
    1596             : {
    1597           0 :     return generateAddress2dString( BinAddress( rAddress ), bAbsolute );
    1598             : }
    1599             : 
    1600           0 : OUString FormulaProcessorBase::generateAddress2dString( const BinAddress& rAddress, bool bAbsolute )
    1601             : {
    1602           0 :     OUStringBuffer aBuffer;
    1603             :     // column
    1604           0 :     for( sal_Int32 nTemp = rAddress.mnCol; nTemp >= 0; (nTemp /= 26) -= 1 )
    1605           0 :         aBuffer.insert( 0, sal_Unicode( 'A' + (nTemp % 26) ) );
    1606           0 :     if( bAbsolute )
    1607           0 :         aBuffer.insert( 0, '$' );
    1608             :     // row
    1609           0 :     if( bAbsolute )
    1610           0 :         aBuffer.append( '$' );
    1611           0 :     aBuffer.append( static_cast< sal_Int32 >( rAddress.mnRow + 1 ) );
    1612           0 :     return aBuffer.makeStringAndClear();
    1613             : }
    1614             : 
    1615          78 : OUString FormulaProcessorBase::generateApiString( const OUString& rString )
    1616             : {
    1617          78 :     OUString aRetString = rString;
    1618          78 :     sal_Int32 nQuotePos = aRetString.getLength();
    1619         156 :     while( (nQuotePos = aRetString.lastIndexOf( '"', nQuotePos )) >= 0 )
    1620           0 :         aRetString = aRetString.replaceAt( nQuotePos, 1, OUString( "\"\"" ) );
    1621          78 :     return OUStringBuffer().append( '"' ).append( aRetString ).append( '"' ).makeStringAndClear();
    1622             : }
    1623             : 
    1624          20 : OUString FormulaProcessorBase::generateApiArray( const Matrix< Any >& rMatrix )
    1625             : {
    1626             :     OSL_ENSURE( !rMatrix.empty(), "FormulaProcessorBase::generateApiArray - missing matrix values" );
    1627          20 :     OUStringBuffer aBuffer;
    1628          20 :     aBuffer.append( API_TOKEN_ARRAY_OPEN );
    1629          40 :     for( size_t nRow = 0, nHeight = rMatrix.height(); nRow < nHeight; ++nRow )
    1630             :     {
    1631          20 :         if( nRow > 0 )
    1632           0 :             aBuffer.append( API_TOKEN_ARRAY_ROWSEP );
    1633          98 :         for( Matrix< Any >::const_iterator aBeg = rMatrix.row_begin( nRow ), aIt = aBeg, aEnd = rMatrix.row_end( nRow ); aIt != aEnd; ++aIt )
    1634             :         {
    1635          78 :             double fValue = 0.0;
    1636          78 :             OUString aString;
    1637          78 :             if( aIt != aBeg )
    1638          58 :                 aBuffer.append( API_TOKEN_ARRAY_COLSEP );
    1639          78 :             if( *aIt >>= fValue )
    1640           0 :                 aBuffer.append( fValue );
    1641          78 :             else if( *aIt >>= aString )
    1642          78 :                 aBuffer.append( generateApiString( aString ) );
    1643             :             else
    1644           0 :                 aBuffer.appendAscii( "\"\"" );
    1645          78 :         }
    1646             :     }
    1647          20 :     aBuffer.append( API_TOKEN_ARRAY_CLOSE );
    1648          20 :     return aBuffer.makeStringAndClear();
    1649             : }
    1650             : 
    1651           2 : Any FormulaProcessorBase::extractReference( const ApiTokenSequence& rTokens ) const
    1652             : {
    1653           2 :     ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES, true );
    1654           2 :     if( aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) )
    1655             :     {
    1656           2 :         Any aRefAny = aTokenIt->Data;
    1657           2 :         if( !(++aTokenIt).is() && (aRefAny.has< SingleReference >() || aRefAny.has< ComplexReference >()) )
    1658           2 :             return aRefAny;
    1659             :     }
    1660           0 :     return Any();
    1661             : }
    1662             : 
    1663           2 : bool FormulaProcessorBase::extractCellRange( CellRangeAddress& orRange,
    1664             :         const ApiTokenSequence& rTokens, bool bAllowRelative ) const
    1665             : {
    1666           2 :     ApiCellRangeList aRanges;
    1667           2 :     lclProcessRef( aRanges, extractReference( rTokens ), bAllowRelative, -1 );
    1668           2 :     if( !aRanges.empty() )
    1669             :     {
    1670           2 :         orRange = aRanges.front();
    1671           2 :         return true;
    1672             :     }
    1673           0 :     return false;
    1674             : }
    1675             : 
    1676           0 : void FormulaProcessorBase::extractCellRangeList( ApiCellRangeList& orRanges,
    1677             :         const ApiTokenSequence& rTokens, bool bAllowRelative, sal_Int32 nFilterBySheet ) const
    1678             : {
    1679           0 :     orRanges.clear();
    1680           0 :     TokenToRangeListState eState = STATE_OPEN;
    1681           0 :     sal_Int32 nParenLevel = 0;
    1682           0 :     for( ApiTokenIterator aIt( rTokens, OPCODE_SPACES, true ); aIt.is() && (eState != STATE_ERROR); ++aIt )
    1683             :     {
    1684           0 :         sal_Int32 nOpCode = aIt->OpCode;
    1685           0 :         switch( eState )
    1686             :         {
    1687             :             // #i107275# accept OPCODE_SEP and OPCODE_LIST as separator token
    1688             :             case STATE_REF:
    1689           0 :                      if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
    1690           0 :                 else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
    1691           0 :                 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
    1692           0 :                 else                               eState = STATE_ERROR;
    1693           0 :             break;
    1694             :             case STATE_SEP:
    1695           0 :                      if( nOpCode == OPCODE_PUSH )  eState = lclProcessRef( orRanges, aIt->Data, bAllowRelative, nFilterBySheet );
    1696           0 :                 else if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
    1697           0 :                 else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
    1698           0 :                 else if( nOpCode == OPCODE_OPEN )  eState = lclProcessOpen( nParenLevel );
    1699           0 :                 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
    1700           0 :                 else                               eState = STATE_ERROR;
    1701           0 :             break;
    1702             :             case STATE_OPEN:
    1703           0 :                      if( nOpCode == OPCODE_PUSH )  eState = lclProcessRef( orRanges, aIt->Data, bAllowRelative, nFilterBySheet );
    1704           0 :                 else if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
    1705           0 :                 else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
    1706           0 :                 else if( nOpCode == OPCODE_OPEN )  eState = lclProcessOpen( nParenLevel );
    1707           0 :                 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
    1708           0 :                 else                               eState = STATE_ERROR;
    1709           0 :             break;
    1710             :             case STATE_CLOSE:
    1711           0 :                      if( nOpCode == OPCODE_SEP )   eState = STATE_SEP;
    1712           0 :                 else if( nOpCode == OPCODE_LIST )  eState = STATE_SEP;
    1713           0 :                 else if( nOpCode == OPCODE_CLOSE ) eState = lclProcessClose( nParenLevel );
    1714           0 :                 else                               eState = STATE_ERROR;
    1715           0 :             break;
    1716             :             default:;
    1717             :         }
    1718             :     }
    1719             : 
    1720           0 :     if( eState == STATE_ERROR )
    1721           0 :         orRanges.clear();
    1722             :     else
    1723           0 :         getAddressConverter().validateCellRangeList( orRanges, false );
    1724           0 : }
    1725             : 
    1726           0 : bool FormulaProcessorBase::extractString( OUString& orString, const ApiTokenSequence& rTokens ) const
    1727             : {
    1728           0 :     ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES, true );
    1729           0 :     return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_PUSH) && (aTokenIt->Data >>= orString) && !(++aTokenIt).is();
    1730             : }
    1731             : 
    1732           0 : bool FormulaProcessorBase::extractSpecialTokenInfo( ApiSpecialTokenInfo& orTokenInfo, const ApiTokenSequence& rTokens ) const
    1733             : {
    1734           0 :     ApiTokenIterator aTokenIt( rTokens, OPCODE_SPACES, true );
    1735           0 :     return aTokenIt.is() && (aTokenIt->OpCode == OPCODE_BAD) && (aTokenIt->Data >>= orTokenInfo);
    1736             : }
    1737             : 
    1738           0 : void FormulaProcessorBase::convertStringToStringList(
    1739             :         ApiTokenSequence& orTokens, sal_Unicode cStringSep, bool bTrimLeadingSpaces ) const
    1740             : {
    1741           0 :     OUString aString;
    1742           0 :     if( extractString( aString, orTokens ) && !aString.isEmpty() )
    1743             :     {
    1744           0 :         ::std::vector< ApiToken > aNewTokens;
    1745           0 :         sal_Int32 nPos = 0;
    1746           0 :         sal_Int32 nLen = aString.getLength();
    1747           0 :         while( (0 <= nPos) && (nPos < nLen) )
    1748             :         {
    1749           0 :             OUString aEntry = aString.getToken( 0, cStringSep, nPos );
    1750           0 :             if( bTrimLeadingSpaces )
    1751             :             {
    1752           0 :                 sal_Int32 nStart = 0;
    1753           0 :                 while( (nStart < aEntry.getLength()) && (aEntry[ nStart ] == ' ') ) ++nStart;
    1754           0 :                 aEntry = aEntry.copy( nStart );
    1755             :             }
    1756           0 :             if( !aNewTokens.empty() )
    1757           0 :                 aNewTokens.push_back( ApiToken( OPCODE_SEP, Any() ) );
    1758           0 :             aNewTokens.push_back( ApiToken( OPCODE_PUSH, Any( aEntry ) ) );
    1759           0 :         }
    1760           0 :         orTokens = ContainerHelper::vectorToSequence( aNewTokens );
    1761           0 :     }
    1762           0 : }
    1763             : 
    1764             : } // namespace xls
    1765          48 : } // namespace oox
    1766             : 
    1767             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10