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