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