LibreOffice Module sc (master) 1
formulaparser.cxx
Go to the documentation of this file.
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 <formulaparser.hxx>
21
22#include <com/sun/star/sheet/ComplexReference.hpp>
23#include <com/sun/star/sheet/ExternalReference.hpp>
24#include <com/sun/star/sheet/ReferenceFlags.hpp>
25#include <com/sun/star/sheet/SingleReference.hpp>
26#include <com/sun/star/table/CellAddress.hpp>
27#include <osl/diagnose.h>
28#include <sal/log.hxx>
30#include <oox/token/properties.hxx>
32#include <addressconverter.hxx>
33#include <biffhelper.hxx>
34#include <defnamesbuffer.hxx>
36#include <tablebuffer.hxx>
37#include <o3tl/string_view.hxx>
38
39namespace oox::xls {
40
41using namespace ::com::sun::star::sheet;
42using namespace ::com::sun::star::sheet::ReferenceFlags;
43using namespace ::com::sun::star::table;
44using namespace ::com::sun::star::uno;
45
46// formula finalizer ==========================================================
47
49 OpCodeProvider( rOpCodeProv ),
50 ApiOpCodes( getOpCodes() )
51{
52 maTokens.reserve( 0x2000 );
53}
54
56{
58 if( rTokens.hasElements() )
59 {
60 const ApiToken* pToken = rTokens.getConstArray();
61 processTokens( pToken, pToken + rTokens.getLength() );
62 }
63 return maTokens.toSequence();
64}
65
67{
68 return nullptr;
69}
70
71OUString FormulaFinalizer::resolveDefinedName( sal_Int32 ) const
72{
73 return OUString();
74}
75
77{
78 // first, try to find a regular function info from token op-code
79 if( const FunctionInfo* pRegFuncInfo = getFuncInfoFromApiToken( orFuncToken ) )
80 return pRegFuncInfo;
81
82 // try to recognize a function from an external library
83 if( (orFuncToken.OpCode == OPCODE_BAD) && orFuncToken.Data.has< OUString >() )
84 {
85 // virtual call to resolveBadFuncName()
86 if( const FunctionInfo* pLibFuncInfo = resolveBadFuncName( orFuncToken.Data.get< OUString >() ) )
87 {
88 // write function op-code to the OPCODE_BAD token
89 orFuncToken.OpCode = pLibFuncInfo->mnApiOpCode;
90 // if it is an external function, insert programmatic function name
91 if( (orFuncToken.OpCode == OPCODE_EXTERNAL) && (!pLibFuncInfo->maExtProgName.isEmpty()) )
92 orFuncToken.Data <<= pLibFuncInfo->maExtProgName;
93 else
94 orFuncToken.Data.clear(); // clear string from OPCODE_BAD
95 return pLibFuncInfo;
96 }
97 }
98
99 // no success - return null
100 return nullptr;
101}
102
104{
105 // try to resolve the passed token to a supported sheet function
106 if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
107 {
108 orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
109 // programmatic add-in function name
110 if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && !pFuncInfo->maExtProgName.isEmpty() )
111 orFuncToken.Data <<= pFuncInfo->maExtProgName;
112 // name of unsupported function, convert to OPCODE_BAD to preserve the name
113 else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && !pFuncInfo->maOoxFuncName.isEmpty() )
114 orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
115 return pFuncInfo;
116 }
117
118 // macro call or unknown function name, move data to function token
119 if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
120 orFuncToken = rECToken;
121
122 // defined name used as function call, convert to OPCODE_BAD to preserve the name
123 if( (rECToken.OpCode == OPCODE_NAME) && rECToken.Data.has< sal_Int32 >() )
124 {
125 OUString aDefName = resolveDefinedName( rECToken.Data.get< sal_Int32 >() );
126 if( !aDefName.isEmpty() )
127 {
128 orFuncToken.OpCode = OPCODE_BAD;
129 orFuncToken.Data <<= aDefName;
130 }
131 }
132
133 return nullptr;
134}
135
136void FormulaFinalizer::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
137{
138 while( pToken < pTokenEnd )
139 {
140 // push the current token into the vector
141 bool bValid = appendFinalToken( *pToken );
142 // try to process a function
143 if( const FunctionInfo* pFuncInfo = bValid ? getFunctionInfo( maTokens.back() ) : nullptr )
144 pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
145 // otherwise, go to next token
146 else
147 ++pToken;
148 }
149}
150
152 const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
153{
154 // remember position of the token containing the function op-code
155 size_t nFuncNameIdx = maTokens.size() - 1;
156
157 // process a function, if an OPCODE_OPEN token is following
158 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::processParameters - OPCODE_OPEN expected" );
159 if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
160 {
161 // append the OPCODE_OPEN token to the vector
163
164 // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
165 ParameterPosVector aParams;
166 pToken = findParameters( aParams, pToken, pTokenEnd );
167 OSL_ENSURE( aParams.size() >= 2, "FormulaFinalizer::processParameters - missing tokens" );
168 size_t nParamCount = aParams.size() - 1;
169
170 if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
171 {
172 /* Empty pair of parentheses -> function call without parameters,
173 process parameter, there might be spaces between parentheses. */
174 processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
175 }
176 else
177 {
178 const FunctionInfo* pRealFuncInfo = &rFuncInfo;
179 ParameterPosVector::const_iterator aPosIt = aParams.begin();
180
181 /* Preprocess EXTERN.CALL functions. The actual function name is
182 contained as reference to a defined name in the first (hidden)
183 parameter. */
184 if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
185 {
186 ApiToken& rFuncToken = maTokens[ nFuncNameIdx ];
187 rFuncToken.OpCode = OPCODE_NONAME;
188
189 // try to initialize function token from first parameter
190 if( const ApiToken* pECToken = getSingleToken( *aPosIt + 1, *(aPosIt + 1) ) )
191 if( const FunctionInfo* pECFuncInfo = getExternCallInfo( rFuncToken, *pECToken ) )
192 pRealFuncInfo = pECFuncInfo;
193
194 /* On success (something has been inserted into rFuncToken),
195 skip the first parameter. */
196 if( rFuncToken.OpCode != OPCODE_NONAME )
197 {
198 --nParamCount;
199 ++aPosIt;
200 }
201 }
202
203 // process all parameters
204 FunctionParamInfoIterator aParamInfoIt( *pRealFuncInfo );
205 size_t nLastValidSize = maTokens.size();
206 size_t nLastValidCount = 0;
207 for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aParamInfoIt )
208 {
209 // add embedded Calc-only parameters
210 if( aParamInfoIt.isCalcOnlyParam() )
211 {
212 appendCalcOnlyParameter( *pRealFuncInfo, nParam, nParamCount );
213 while( aParamInfoIt.isCalcOnlyParam() ) ++aParamInfoIt;
214 }
215
216 const ApiToken* pParamBegin = *aPosIt + 1;
217 const ApiToken* pParamEnd = *(aPosIt + 1);
218 bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
219
220 if( !aParamInfoIt.isExcelOnlyParam() )
221 {
222 // handle empty parameters
223 if( bIsEmpty )
224 {
225 // append leading space tokens from original token array
226 while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
227 maTokens.push_back( *pParamBegin++ );
228 // add default values for some empty parameters, or the OPCODE_MISSING token
229 appendEmptyParameter( *pRealFuncInfo, nParam );
230 // reset bIsEmpty flag, if something has been appended in appendEmptyParameter()
231 bIsEmpty = maTokens.back().OpCode == OPCODE_MISSING;
232 // skip OPCODE_MISSING token in the original token array
233 OSL_ENSURE( (pParamBegin == pParamEnd) || (pParamBegin->OpCode == OPCODE_MISSING), "FormulaFinalizer::processParameters - OPCODE_MISSING expected" );
234 if( pParamBegin < pParamEnd ) ++pParamBegin;
235 // append trailing space tokens from original token array
236 while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
237 maTokens.push_back( *pParamBegin++ );
238 }
239 else
240 {
241 // if parameter is not empty, process all tokens of the parameter
242 processTokens( pParamBegin, pParamEnd );
243 }
244
245 // append parameter separator token
247 }
248
249 /* #84453# Update size of new token sequence with valid parameters
250 to be able to remove trailing optional empty parameters. */
251 if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
252 {
253 nLastValidSize = maTokens.size();
254 nLastValidCount = nParam + 1;
255 }
256 }
257
258 // #84453# remove trailing optional empty parameters
259 maTokens.resize( nLastValidSize );
260
261 // add trailing Calc-only parameters
262 if( aParamInfoIt.isCalcOnlyParam() )
263 appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount, nParamCount );
264
265 // add optional parameters that are required in Calc
266 appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
267
268 // remove last parameter separator token
269 if( maTokens.back().OpCode == OPCODE_SEP )
271 }
272
273 /* Append the OPCODE_CLOSE token to the vector, but only if there is
274 no OPCODE_BAD token at the end, this token already contains the
275 trailing closing parentheses. */
276 if( (pTokenEnd - 1)->OpCode != OPCODE_BAD )
278 }
279
280 /* Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
281 if no matching add-in function was found. */
282 ApiToken& rFuncNameToken = maTokens[ nFuncNameIdx ];
283 if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
284 rFuncNameToken.OpCode = OPCODE_NONAME;
285
286 return pToken;
287}
288
289bool FormulaFinalizer::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
290{
291 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
292 if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
293 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
294 return pToken == pTokenEnd;
295}
296
297const ApiToken* FormulaFinalizer::getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
298{
299 const ApiToken* pSingleToken = nullptr;
300 // skip leading whitespace tokens
301 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
302 // remember first non-whitespace token
303 if( pToken < pTokenEnd ) pSingleToken = pToken++;
304 // skip trailing whitespace tokens
305 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
306 // return null, if other non-whitespace tokens follow
307 return (pToken == pTokenEnd) ? pSingleToken : nullptr;
308}
309
310const ApiToken* FormulaFinalizer::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
311{
312 // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
313 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
314 ++pToken;
315 while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
316 {
317 if( pToken->OpCode == OPCODE_OPEN )
318 pToken = skipParentheses( pToken, pTokenEnd );
319 else
320 ++pToken;
321 }
322 // skip the OPCODE_CLOSE token
323 OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
324 return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
325}
326
328 const ApiToken* pToken, const ApiToken* pTokenEnd ) const
329{
330 // push position of OPCODE_OPEN
331 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::findParameters - OPCODE_OPEN expected" );
332 rParams.push_back( pToken++ );
333
334 // find positions of parameter separators
335 while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
336 {
337 if( pToken->OpCode == OPCODE_OPEN )
338 pToken = skipParentheses( pToken, pTokenEnd );
339 else if( pToken->OpCode == OPCODE_SEP )
340 rParams.push_back( pToken++ );
341 else
342 ++pToken;
343 }
344
345 // push position of OPCODE_CLOSE
346 OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaFinalizer::findParameters - OPCODE_CLOSE expected" );
347 rParams.push_back( pToken );
348 return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
349}
350
351void FormulaFinalizer::appendEmptyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
352{
353 // remember old size of the token array
354 size_t nTokenArraySize = maTokens.size();
355
356 switch( rFuncInfo.mnBiff12FuncId )
357 {
358 case BIFF_FUNC_IF:
359 if( (nParam == 1) || (nParam == 2) )
360 maTokens.append< double >( OPCODE_PUSH, 0.0 );
361 break;
362 default:;
363 }
364
365 // if no token has been added, append an OPCODE_MISSING token
366 if( nTokenArraySize == maTokens.size() )
368}
369
370void FormulaFinalizer::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam, size_t nParamCount )
371{
372 switch( rFuncInfo.mnBiff12FuncId )
373 {
374 case BIFF_FUNC_FLOOR:
376 if (nParam == 2 && nParamCount < 3)
377 {
378 maTokens.append< double >( OPCODE_PUSH, 1.0 );
380 }
381 break;
382 }
383}
384
385void FormulaFinalizer::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
386{
387 switch( rFuncInfo.mnBiff12FuncId )
388 {
390 if( nParamCount == 1 )
391 {
392 maTokens.append< double >( OPCODE_PUSH, 1.0 );
394 }
395 break;
396 }
397}
398
400{
401 // replace OPCODE_MACRO without macro name with #NAME? error code
402 bool bValid = (rToken.OpCode != OPCODE_MACRO) || rToken.Data.hasValue();
403 if( bValid )
404 {
405 maTokens.push_back( rToken );
406 }
407 else
408 {
412 }
413 return bValid;
414}
415
416// parser implementation base =================================================
417
419{
420public:
421 explicit FormulaParserImpl( const FormulaParser& rParent );
422
425 const ScAddress& rBaseAddress,
426 const OUString& rFormulaString );
427
430 const ScAddress& rBaseAddress,
433
435 OUString resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const;
436
437protected:
438 typedef ::std::pair< sal_Int32, bool > WhiteSpace;
439 typedef ::std::vector< WhiteSpace > WhiteSpaceVec;
440
442 void initializeImport( const ScAddress& rBaseAddress, FormulaType eType );
445
446 // token array ------------------------------------------------------------
447
448 bool resetSpaces();
449 static void appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed );
450 void appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed );
451 void appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed );
452 void appendClosingSpaces( sal_Int32 nCount, bool bLineFeed );
453
454 size_t getFormulaSize() const;
455 Any& appendRawToken( sal_Int32 nOpCode );
456 Any& insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd );
457 size_t appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces );
458 size_t insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd );
459
460 size_t getOperandSize( size_t nOpIndex ) const;
461 void pushOperandSize( size_t nSize );
462 size_t popOperandSize();
463
464 ApiToken& getOperandToken( size_t nOpIndex, size_t nTokenIndex );
465
466 bool pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = nullptr );
467 template< typename Type >
468 bool pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = nullptr );
469 template< typename Type >
470 bool pushValueOperandToken( const Type& rValue )
471 { return pushValueOperandToken( rValue, OPCODE_PUSH, nullptr ); }
472 bool pushParenthesesOperandToken( const WhiteSpaceVec* pClosingSpaces = nullptr );
473 bool pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = nullptr );
474 bool pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = nullptr );
475 bool pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = nullptr );
476 bool pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces = nullptr, const WhiteSpaceVec* pClosingSpaces = nullptr );
477 bool pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = nullptr, const WhiteSpaceVec* pClosingSpaces = nullptr );
478 bool pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = nullptr, const WhiteSpaceVec* pClosingSpaces = nullptr );
479
480 bool pushOperand( sal_Int32 nOpCode );
481 template< typename Type >
482 bool pushValueOperand( const Type& rValue, sal_Int32 nOpCode );
483 template< typename Type >
484 bool pushValueOperand( const Type& rValue )
485 { return pushValueOperand( rValue, OPCODE_PUSH ); }
486 bool pushBoolOperand( bool bValue );
487 bool pushErrorOperand( double fEncodedError );
488 bool pushBiffBoolOperand( sal_uInt8 nValue );
489 bool pushBiffErrorOperand( sal_uInt8 nErrorCode );
490 bool pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
491 bool pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
492 template< typename Type >
493 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef );
494 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
495 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
496 bool pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken );
497 bool pushDefinedNameOperand( const DefinedNameRef& rxDefName );
498 bool pushExternalFuncOperand( const FunctionInfo& rFuncInfo );
499 bool pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem );
500 bool pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink );
501 bool pushSpecialTokenOperand( const BinAddress& rBaseAddr );
502
503 bool pushUnaryPreOperator( sal_Int32 nOpCode );
504 bool pushUnaryPostOperator( sal_Int32 nOpCode );
505 bool pushBinaryOperator( sal_Int32 nOpCode );
507 bool pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount );
508 bool pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount );
509
510private:
511 // reference conversion ---------------------------------------------------
512
513 void initReference2d( SingleReference& orApiRef ) const;
514 static void initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet );
515 void convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
516 void convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
517 void convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
518 void convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
519 void convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
520 void convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
521
522private:
523 // finalize token sequence ------------------------------------------------
524
525 virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const override;
526 virtual OUString resolveDefinedName( sal_Int32 nTokenIndex ) const override;
527
528protected:
529 const sal_Int32 mnMaxApiCol;
530 const sal_Int32 mnMaxApiRow;
531 const sal_Int32 mnMaxXlsCol;
532 const sal_Int32 mnMaxXlsRow;
533
538
539private:
541 std::vector<size_t> maTokenIndexes;
542 std::vector<size_t> maOperandSizeStack;
546};
547
549 FormulaFinalizer( rParent ),
550 WorkbookHelper( rParent ),
551 mnMaxApiCol( rParent.getAddressConverter().getMaxApiAddress().Col() ),
552 mnMaxApiRow( rParent.getAddressConverter().getMaxApiAddress().Row() ),
553 mnMaxXlsCol( rParent.getAddressConverter().getMaxXlsAddress().Col() ),
554 mnMaxXlsRow( rParent.getAddressConverter().getMaxXlsAddress().Row() ),
555 mbRelativeAsOffset( false ),
556 mb2dRefsAs3dRefs( false ),
557 mbSpecialTokens( false )
558{
559 // reserve enough space to make resize(), push_back() etc. cheap
560 maTokenStorage.reserve( 0x2000 );
561 maTokenIndexes.reserve( 0x2000 );
562 maOperandSizeStack.reserve( 256 );
563 maLeadingSpaces.reserve( 256 );
564 maOpeningSpaces.reserve( 256 );
565 maClosingSpaces.reserve( 256 );
566}
567
569{
570 OSL_FAIL( "FormulaParserImpl::importOoxFormula - not implemented" );
571 return ApiTokenSequence();
572}
573
575{
576 SAL_WARN("sc.filter", "FormulaParserImpl::importBiff12Formula - not implemented" );
577 return ApiTokenSequence();
578}
579
580OUString FormulaParserImpl::resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const
581{
582 const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, bUseRefSheets ).get();
583 OSL_ENSURE( pExtLink && (pExtLink->getLinkType() == ExternalLinkType::OLE), "FormulaParserImpl::resolveOleTarget - missing or wrong link" );
584 if( pExtLink && (pExtLink->getLinkType() == ExternalLinkType::OLE) )
585 return getBaseFilter().getAbsoluteUrl( pExtLink->getTargetUrl() );
586 return OUString();
587}
588
590{
591 maBaseAddr = rBaseAddr;
593 switch( eType )
594 {
596 mbSpecialTokens = true;
597 break;
599 break;
601 mbRelativeAsOffset = true;
602 break;
604 mbRelativeAsOffset = true;
605 break;
607 mbRelativeAsOffset = true;
608 break;
609 }
610
612 maTokenIndexes.clear();
613 maOperandSizeStack.clear();
614}
615
617{
618 ApiTokenSequence aTokens( static_cast< sal_Int32 >( maTokenIndexes.size() ) );
619 if( aTokens.hasElements() )
620 {
621 ApiToken* pToken = aTokens.getArray();
622 for( const auto& tokenIndex : maTokenIndexes )
623 {
624 *pToken = maTokenStorage[ tokenIndex ];
625 ++pToken;
626 }
627 }
628 return finalizeTokenArray( aTokens );
629}
630
631// token array ----------------------------------------------------------------
632
634{
635 maLeadingSpaces.clear();
636 maOpeningSpaces.clear();
637 maClosingSpaces.clear();
638 return true;
639}
640
641void FormulaParserImpl::appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed )
642{
643 OSL_ENSURE( nCount >= 0, "FormulaParserImpl::appendSpaces - negative count" );
644 if( nCount > 0 )
645 orSpaces.emplace_back( nCount, bLineFeed );
646}
647
648void FormulaParserImpl::appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed )
649{
650 appendSpaces( maLeadingSpaces, nCount, bLineFeed );
651}
652
653void FormulaParserImpl::appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed )
654{
655 appendSpaces( maOpeningSpaces, nCount, bLineFeed );
656}
657
658void FormulaParserImpl::appendClosingSpaces( sal_Int32 nCount, bool bLineFeed )
659{
660 appendSpaces( maClosingSpaces, nCount, bLineFeed );
661}
662
664{
665 return maTokenIndexes.size();
666}
667
669{
670 maTokenIndexes.push_back( maTokenStorage.size() );
671 return maTokenStorage.append( nOpCode );
672}
673
674Any& FormulaParserImpl::insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd )
675{
676 maTokenIndexes.insert( maTokenIndexes.end() - nIndexFromEnd, maTokenStorage.size() );
677 return maTokenStorage.append( nOpCode );
678}
679
681{
682 if( pSpaces )
683 for( const auto& rSpace : *pSpaces )
684 appendRawToken( OPCODE_SPACES ) <<= rSpace.first;
685 return pSpaces ? pSpaces->size() : 0;
686}
687
688size_t FormulaParserImpl::insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd )
689{
690 if( pSpaces )
691 for( const auto& rSpace : *pSpaces )
692 insertRawToken( OPCODE_SPACES, nIndexFromEnd ) <<= rSpace.first;
693 return pSpaces ? pSpaces->size() : 0;
694}
695
696size_t FormulaParserImpl::getOperandSize( size_t nOpIndex ) const
697{
698 OSL_ENSURE( (nOpIndex < 1) && (!maOperandSizeStack.empty()),
699 "FormulaParserImpl::getOperandSize - invalid parameters" );
700 return maOperandSizeStack[ maOperandSizeStack.size() - 1 + nOpIndex ];
701}
702
704{
705 maOperandSizeStack.push_back( nSize );
706}
707
709{
710 OSL_ENSURE( !maOperandSizeStack.empty(), "FormulaParserImpl::popOperandSize - invalid call" );
711 size_t nOpSize = maOperandSizeStack.back();
712 maOperandSizeStack.pop_back();
713 return nOpSize;
714}
715
716ApiToken& FormulaParserImpl::getOperandToken( size_t nOpIndex, size_t nTokenIndex )
717{
718 SAL_WARN_IF( getOperandSize( nOpIndex ) <= nTokenIndex, "sc.filter",
719 "FormulaParserImpl::getOperandToken - invalid parameters" );
720 auto aIndexIt = maTokenIndexes.cend();
721 for( auto aEnd = maOperandSizeStack.cend(), aIt = aEnd - 1 + nOpIndex; aIt != aEnd; ++aIt )
722 aIndexIt -= *aIt;
723 return maTokenStorage[ *(aIndexIt + nTokenIndex) ];
724}
725
726bool FormulaParserImpl::pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
727{
728 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
729 appendRawToken( nOpCode );
730 pushOperandSize( nSpacesSize + 1 );
731 return true;
732}
733
734template< typename Type >
735bool FormulaParserImpl::pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
736{
737 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
738 appendRawToken( nOpCode ) <<= rValue;
739 pushOperandSize( nSpacesSize + 1 );
740 return true;
741}
742
744{
745 size_t nSpacesSize = appendWhiteSpaceTokens( nullptr );
747 nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
749 pushOperandSize( nSpacesSize + 2 );
750 return true;
751}
752
753bool FormulaParserImpl::pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
754{
755 bool bOk = !maOperandSizeStack.empty();
756 if( bOk )
757 {
758 size_t nOpSize = popOperandSize();
759 size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOpSize );
760 insertRawToken( nOpCode, nOpSize );
761 pushOperandSize( nOpSize + nSpacesSize + 1 );
762 }
763 return bOk;
764}
765
766bool FormulaParserImpl::pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
767{
768 bool bOk = !maOperandSizeStack.empty();
769 if( bOk )
770 {
771 size_t nOpSize = popOperandSize();
772 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
773 appendRawToken( nOpCode );
774 pushOperandSize( nOpSize + nSpacesSize + 1 );
775 }
776 return bOk;
777}
778
779bool FormulaParserImpl::pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
780{
781 bool bOk = maOperandSizeStack.size() >= 2;
782 if( bOk )
783 {
784 size_t nOp2Size = popOperandSize();
785 size_t nOp1Size = popOperandSize();
786 size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOp2Size );
787 insertRawToken( nOpCode, nOp2Size );
788 pushOperandSize( nOp1Size + nSpacesSize + 1 + nOp2Size );
789 }
790 return bOk;
791}
792
793bool FormulaParserImpl::pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
794{
795 bool bOk = !maOperandSizeStack.empty();
796 if( bOk )
797 {
798 size_t nOpSize = popOperandSize();
799 size_t nSpacesSize = insertWhiteSpaceTokens( pOpeningSpaces, nOpSize );
800 insertRawToken( OPCODE_OPEN, nOpSize );
801 nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
803 pushOperandSize( nOpSize + nSpacesSize + 2 );
804 }
805 return bOk;
806}
807
808bool FormulaParserImpl::pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
809{
810 /* #i70925# if there are not enough tokens available on token stack, do
811 not exit with error, but reduce parameter count. */
812 nParamCount = ::std::min( maOperandSizeStack.size(), nParamCount );
813
814 // convert all parameters on stack to a single operand separated with OPCODE_SEP
815 bool bOk = true;
816 for( size_t nParam = 1; bOk && (nParam < nParamCount); ++nParam )
818
819 // add function parentheses and function name
820 return bOk &&
821 ((nParamCount > 0) ? pushParenthesesOperatorToken( nullptr, pClosingSpaces ) : pushParenthesesOperandToken( pClosingSpaces )) &&
822 pushUnaryPreOperatorToken( nOpCode, pLeadingSpaces );
823}
824
825bool FormulaParserImpl::pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
826{
827 bool bOk = pushFunctionOperatorToken( rFuncInfo.mnApiOpCode, nParamCount, pLeadingSpaces, pClosingSpaces );
828 if( bOk )
829 {
830 // create an external add-in call for the passed built-in function
831 if( (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) && !rFuncInfo.maExtProgName.isEmpty() )
832 getOperandToken( 0, 0 ).Data <<= rFuncInfo.maExtProgName;
833 // create a bad token with unsupported function name
834 else if( (rFuncInfo.mnApiOpCode == OPCODE_BAD) && !rFuncInfo.maOoxFuncName.isEmpty() )
835 getOperandToken( 0, 0 ).Data <<= rFuncInfo.maOoxFuncName;
836 }
837 return bOk;
838}
839
840bool FormulaParserImpl::pushOperand( sal_Int32 nOpCode )
841{
842 return pushOperandToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
843}
844
845template< typename Type >
846bool FormulaParserImpl::pushValueOperand( const Type& rValue, sal_Int32 nOpCode )
847{
848 return pushValueOperandToken( rValue, nOpCode, &maLeadingSpaces ) && resetSpaces();
849}
850
852{
853 if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( bValue ? BIFF_FUNC_TRUE : BIFF_FUNC_FALSE ) )
854 return pushFunctionOperator( pFuncInfo->mnApiOpCode, 0 );
855 return pushValueOperand< double >( bValue ? 1.0 : 0.0 );
856}
857
858bool FormulaParserImpl::pushErrorOperand( double fEncodedError )
859{
860 // HACK: enclose all error codes into an 1x1 matrix
861 // start token array with opening brace and leading spaces
863 size_t nOpSize = popOperandSize();
864 size_t nOldArraySize = maTokenIndexes.size();
865 // push a double containing the Calc error code
866 appendRawToken( OPCODE_PUSH ) <<= fEncodedError;
867 // close token array and set resulting operand size
869 pushOperandSize( nOpSize + maTokenIndexes.size() - nOldArraySize );
870 return true;
871}
872
874{
876}
877
879{
881}
882
883bool FormulaParserImpl::pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
884{
885 SingleReference aApiRef;
886 convertReference2d( aApiRef, rRef, bDeleted, bRelativeAsOffset );
887 return pushValueOperand( aApiRef );
888}
889
890bool FormulaParserImpl::pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
891{
892 ComplexReference aApiRef;
893 convertReference2d( aApiRef, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
894 return pushValueOperand( aApiRef );
895}
896
897template< typename Type >
898bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef )
899{
900 if( rSheetRange.isExternal() )
901 {
902 ExternalReference aApiExtRef;
903 aApiExtRef.Index = rSheetRange.getDocLinkIndex();
904 aApiExtRef.Reference <<= rApiRef;
905 return pushValueOperand( aApiExtRef );
906 }
907 return pushValueOperand( rApiRef );
908}
909
910bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
911{
912 if( rSheetRange.is3dRange() )
913 {
914 // single-cell-range over several sheets, needs to create a ComplexReference
915 ComplexReference aApiRef;
916 convertReference3d( aApiRef, rSheetRange, rRef, rRef, bDeleted, bRelativeAsOffset );
917 return pushReferenceOperand( rSheetRange, aApiRef );
918 }
919 SingleReference aApiRef;
920 convertReference3d( aApiRef, rSheetRange.getFirstSheet(), rSheetRange.isSameSheet(), rRef, bDeleted, bRelativeAsOffset );
921 return pushReferenceOperand( rSheetRange, aApiRef );
922}
923
924bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
925{
926 ComplexReference aApiRef;
927 convertReference3d( aApiRef, rSheetRange, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
928 return pushReferenceOperand( rSheetRange, aApiRef );
929}
930
931bool FormulaParserImpl::pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken )
932{
933 if( bPushBadToken && !rName.getModelName().isEmpty() && (rName.getModelName()[ 0 ] >= ' ') )
934 return pushValueOperand( rName.getModelName(), OPCODE_BAD );
936}
937
939{
940 if( !rxDefName || rxDefName->getModelName().isEmpty() )
942 if( rxDefName->isMacroFunction() )
943 return pushValueOperand( rxDefName->getModelName(), OPCODE_MACRO );
944 if( rxDefName->getTokenIndex() >= 0 )
945 return pushValueOperand( rxDefName->getTokenIndex(), OPCODE_NAME );
946 return pushEmbeddedRefOperand( *rxDefName, true );
947}
948
950{
951 return (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) ?
953 pushOperand( rFuncInfo.mnApiOpCode );
954}
955
956bool FormulaParserImpl::pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem )
957{
958 // create the function call DDE("server";"topic";"item")
959 return
960 pushValueOperandToken( rDdeServer ) &&
961 pushValueOperandToken( rDdeTopic ) &&
962 pushValueOperandToken( rDdeItem ) &&
964}
965
967{
968 if( rxExtName ) switch( rExtLink.getLinkType() )
969 {
971 return pushEmbeddedRefOperand( *rxExtName, false );
972
974 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
975 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == rExtLink.getFuncLibraryType()) )
976 return pushExternalFuncOperand( *pFuncInfo );
977 break;
978
980 {
981 OUString aDdeServer, aDdeTopic, aDdeItem;
982 if( rxExtName->getDdeLinkData( aDdeServer, aDdeTopic, aDdeItem ) )
983 return pushDdeLinkOperand( aDdeServer, aDdeTopic, aDdeItem );
984 }
985 break;
986
987 default:
988 OSL_ENSURE( rExtLink.getLinkType() != ExternalLinkType::Self, "FormulaParserImpl::pushExternalNameOperand - invalid call" );
989 }
991}
992
994{
995 CellAddress aBaseAddr( maBaseAddr.Tab(), rBaseAddr.mnCol, rBaseAddr.mnRow );
996 ApiSpecialTokenInfo aTokenInfo( aBaseAddr, false );
997 return mbSpecialTokens && (getFormulaSize() == 0) && pushValueOperand( aTokenInfo, OPCODE_BAD );
998}
999
1001{
1002 return pushUnaryPreOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1003}
1004
1006{
1008}
1009
1011{
1012 return pushBinaryOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1013}
1014
1016{
1018}
1019
1020bool FormulaParserImpl::pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount )
1021{
1022 return pushFunctionOperatorToken( nOpCode, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1023}
1024
1025bool FormulaParserImpl::pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount )
1026{
1027 return pushFunctionOperatorToken( rFuncInfo, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1028}
1029
1030// reference conversion -------------------------------------------------------
1031
1032void FormulaParserImpl::initReference2d( SingleReference& orApiRef ) const
1033{
1034 if( mb2dRefsAs3dRefs )
1035 {
1036 initReference3d( orApiRef, sal_Int32 (maBaseAddr.Tab() ), false );
1037 }
1038 else
1039 {
1040 orApiRef.Flags = SHEET_RELATIVE;
1041 // #i10184# absolute sheet index needed for relative references in shared formulas
1042 orApiRef.Sheet = sal_Int32( maBaseAddr.Tab() );
1043 orApiRef.RelativeSheet = 0;
1044 }
1045}
1046
1047void FormulaParserImpl::initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet )
1048{
1049 orApiRef.Flags = SHEET_3D;
1050 if( nSheet < 0 )
1051 {
1052 orApiRef.Sheet = 0;
1053 orApiRef.Flags |= SHEET_DELETED;
1054 }
1055 else if( bSameSheet )
1056 {
1057 OSL_ENSURE( nSheet == 0, "FormulaParserImpl::initReference3d - invalid sheet index" );
1058 orApiRef.Flags |= SHEET_RELATIVE;
1059 orApiRef.RelativeSheet = 0;
1060 }
1061 else
1062 {
1063 orApiRef.Sheet = nSheet;
1064 }
1065}
1066
1067void FormulaParserImpl::convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1068{
1069 if( bDeleted )
1070 {
1071 orApiRef.Column = 0;
1072 orApiRef.Row = 0;
1073 // no explicit information about whether row or column is deleted
1074 orApiRef.Flags |= COLUMN_DELETED | ROW_DELETED;
1075 }
1076 else
1077 {
1078 // column/row indexes and flags
1079 setFlag( orApiRef.Flags, COLUMN_RELATIVE, rRef.mbColRel );
1080 setFlag( orApiRef.Flags, ROW_RELATIVE, rRef.mbRowRel );
1081 (rRef.mbColRel ? orApiRef.RelativeColumn : orApiRef.Column) = rRef.mnCol;
1082 (rRef.mbRowRel ? orApiRef.RelativeRow : orApiRef.Row) = rRef.mnRow;
1083 // convert absolute indexes to relative offsets used in API
1084 if( !bRelativeAsOffset )
1085 {
1086 if( rRef.mbColRel )
1087 orApiRef.RelativeColumn -= sal_Int32( maBaseAddr.Col() );
1088 if( rRef.mbRowRel )
1089 orApiRef.RelativeRow -= maBaseAddr.Row();
1090 }
1091 }
1092}
1093
1094void FormulaParserImpl::convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1095{
1096 convertReference( orApiRef.Reference1, rRef1, bDeleted, bRelativeAsOffset );
1097 convertReference( orApiRef.Reference2, rRef2, bDeleted, bRelativeAsOffset );
1098 /* Handle references to complete rows or columns (e.g. $1:$2 or C:D),
1099 need to expand or shrink to limits of own document. */
1100 if( !bDeleted && !rRef1.mbColRel && !rRef2.mbColRel && (orApiRef.Reference1.Column == 0) && (orApiRef.Reference2.Column == mnMaxXlsCol) )
1101 orApiRef.Reference2.Column = mnMaxApiCol;
1102 if( !bDeleted && !rRef1.mbRowRel && !rRef2.mbRowRel && (orApiRef.Reference1.Row == 0) && (orApiRef.Reference2.Row == mnMaxXlsRow) )
1103 orApiRef.Reference2.Row = mnMaxApiRow;
1104}
1105
1106void FormulaParserImpl::convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1107{
1108 initReference2d( orApiRef );
1109 convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1110}
1111
1112void FormulaParserImpl::convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1113{
1114 initReference2d( orApiRef.Reference1 );
1115 initReference2d( orApiRef.Reference2 );
1116 convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1117 // remove sheet name from second part of reference
1118 setFlag( orApiRef.Reference2.Flags, SHEET_3D, false );
1119}
1120
1121void FormulaParserImpl::convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1122{
1123 initReference3d( orApiRef, nSheet, bSameSheet );
1124 convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1125}
1126
1127void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1128{
1129 bool bSameSheet = rSheetRange.isSameSheet();
1130 initReference3d( orApiRef.Reference1, rSheetRange.getFirstSheet(), bSameSheet );
1131 initReference3d( orApiRef.Reference2, rSheetRange.getLastSheet(), bSameSheet );
1132 convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1133 // remove sheet name from second part of reference
1134 setFlag( orApiRef.Reference2.Flags, SHEET_3D, rSheetRange.is3dRange() );
1135}
1136
1137// finalize token sequence ----------------------------------------------------
1138
1139const FunctionInfo* FormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
1140{
1141 /* Try to parse calls to library functions. The format of such a function
1142 call is "[n]!funcname", n>0 being the link identifier of the function
1143 library spreadsheet file. */
1144 sal_Int32 nBracketOpen = rTokenData.indexOf( '[' );
1145 sal_Int32 nBracketClose = rTokenData.indexOf( ']' );
1146 sal_Int32 nExclamation = rTokenData.indexOf( '!' );
1147 if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < rTokenData.getLength()) )
1148 {
1149 sal_Int32 nRefId = o3tl::toInt32(rTokenData.subView( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ));
1150 const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
1151 if( pExtLink && (pExtLink->getLinkType() == ExternalLinkType::Library) )
1152 {
1153 OUString aFuncName = rTokenData.copy( nExclamation + 1 ).toAsciiUpperCase();
1154 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName ) )
1155 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
1156 return pFuncInfo;
1157 }
1158 }
1159 return nullptr;
1160}
1161
1162OUString FormulaParserImpl::resolveDefinedName( sal_Int32 nTokenIndex ) const
1163{
1164 if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
1165 return pDefName->getCalcName();
1166 return OUString();
1167}
1168
1169// OOXML/BIFF12 parser implementation =========================================
1170
1171namespace {
1172
1173class OoxFormulaParserImpl : public FormulaParserImpl
1174{
1175public:
1176 explicit OoxFormulaParserImpl( const FormulaParser& rParent );
1177
1178 virtual ApiTokenSequence importOoxFormula(
1179 const ScAddress& rBaseAddr,
1180 const OUString& rFormulaString ) override;
1181
1182 virtual ApiTokenSequence importBiff12Formula(
1183 const ScAddress& rBaseAddr,
1184 FormulaType eType,
1185 SequenceInputStream& rStrm ) override;
1186
1187private:
1188 // import token contents and create API formula token ---------------------
1189
1190 bool importAttrToken( SequenceInputStream& rStrm );
1191 bool importSpaceToken( SequenceInputStream& rStrm );
1192 bool importTableToken( SequenceInputStream& rStrm );
1193 bool importArrayToken( SequenceInputStream& rStrm );
1194 bool importRefToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1195 bool importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1196 bool importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1197 bool importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1198 bool importMemAreaToken( SequenceInputStream& rStrm, bool bAddData );
1199 bool importMemFuncToken( SequenceInputStream& rStrm );
1200 bool importNameToken( SequenceInputStream& rStrm );
1201 bool importNameXToken( SequenceInputStream& rStrm );
1202 bool importFuncToken( SequenceInputStream& rStrm );
1203 bool importFuncVarToken( SequenceInputStream& rStrm );
1204 bool importExpToken( SequenceInputStream& rStrm );
1205
1206 LinkSheetRange readSheetRange( SequenceInputStream& rStrm );
1207
1208 void swapStreamPosition( SequenceInputStream& rStrm );
1209 void skipMemAreaAddData( SequenceInputStream& rStrm );
1210
1211 // convert BIN token and push API operand or operator ---------------------
1212
1213 bool pushBiff12Name( sal_Int32 nNameId );
1214 bool pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId );
1215 bool pushBiff12Function( sal_uInt16 nFuncId );
1216 bool pushBiff12Function( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
1217
1218private:
1219 ApiParserWrapper maApiParser;
1220 sal_Int64 mnAddDataPos;
1222};
1223
1224}
1225
1226OoxFormulaParserImpl::OoxFormulaParserImpl( const FormulaParser& rParent ) :
1227 FormulaParserImpl( rParent ),
1228 maApiParser( rParent.getBaseFilter().getModelFactory(), rParent ),
1229 mnAddDataPos( 0 ),
1230 mbNeedExtRefs( true )
1231{
1232}
1233
1234ApiTokenSequence OoxFormulaParserImpl::importOoxFormula( const ScAddress& rBaseAddr, const OUString& rFormulaString )
1235{
1236 if( mbNeedExtRefs )
1237 {
1238 maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
1239 mbNeedExtRefs = false;
1240 }
1241 return finalizeTokenArray( maApiParser.parseFormula( rFormulaString, rBaseAddr ) );
1242}
1243
1244ApiTokenSequence OoxFormulaParserImpl::importBiff12Formula( const ScAddress& rBaseAddr, FormulaType eType, SequenceInputStream& rStrm )
1245{
1246 initializeImport( rBaseAddr, eType );
1247
1248 sal_Int32 nFmlaSize = rStrm.readInt32();
1249 sal_Int64 nFmlaPos = rStrm.tell();
1250 sal_Int64 nFmlaEndPos = nFmlaPos + nFmlaSize;
1251
1252 rStrm.seek( nFmlaEndPos );
1253 sal_Int32 nAddDataSize = rStrm.readInt32();
1254 mnAddDataPos = rStrm.tell();
1255 sal_Int64 nAddDataEndPos = mnAddDataPos + nAddDataSize;
1256 rStrm.seek( nFmlaPos );
1257
1258 bool bOk = (nFmlaSize >= 0) && (nAddDataSize >= 0);
1259 bool bRelativeAsOffset = mbRelativeAsOffset;
1260
1261 while( bOk && !rStrm.isEof() && (rStrm.tell() < nFmlaEndPos) )
1262 {
1263 sal_uInt8 nTokenId;
1264 nTokenId = rStrm.readuChar();
1265 sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
1266 sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
1267
1268 if( nTokenClass == BIFF_TOKCLASS_NONE )
1269 {
1270 // base tokens
1271 switch( nBaseId )
1272 {
1273 case BIFF_TOKID_EXP: bOk = importExpToken( rStrm ); break;
1274 case BIFF_TOKID_ADD: bOk = pushBinaryOperator( OPCODE_ADD ); break;
1275 case BIFF_TOKID_SUB: bOk = pushBinaryOperator( OPCODE_SUB ); break;
1276 case BIFF_TOKID_MUL: bOk = pushBinaryOperator( OPCODE_MULT ); break;
1277 case BIFF_TOKID_DIV: bOk = pushBinaryOperator( OPCODE_DIV ); break;
1278 case BIFF_TOKID_POWER: bOk = pushBinaryOperator( OPCODE_POWER ); break;
1279 case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( OPCODE_CONCAT ); break;
1280 case BIFF_TOKID_LT: bOk = pushBinaryOperator( OPCODE_LESS ); break;
1281 case BIFF_TOKID_LE: bOk = pushBinaryOperator( OPCODE_LESS_EQUAL ); break;
1282 case BIFF_TOKID_EQ: bOk = pushBinaryOperator( OPCODE_EQUAL ); break;
1283 case BIFF_TOKID_GE: bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL ); break;
1284 case BIFF_TOKID_GT: bOk = pushBinaryOperator( OPCODE_GREATER ); break;
1285 case BIFF_TOKID_NE: bOk = pushBinaryOperator( OPCODE_NOT_EQUAL ); break;
1286 case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( OPCODE_INTERSECT ); break;
1287 case BIFF_TOKID_LIST: bOk = pushBinaryOperator( OPCODE_LIST ); break;
1288 case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( OPCODE_RANGE ); break;
1289 case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN ); break;
1290 case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN ); break;
1291 case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( OPCODE_PERCENT ); break;
1292 case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
1293 case BIFF_TOKID_MISSARG: bOk = pushOperand( OPCODE_MISSING ); break;
1294 case BIFF_TOKID_STR: bOk = pushValueOperand( BiffHelper::readString( rStrm, false ) ); break;
1295 case BIFF_TOKID_NLR: bOk = importTableToken( rStrm ); break;
1296 case BIFF_TOKID_ATTR: bOk = importAttrToken( rStrm ); break;
1297 case BIFF_TOKID_ERR: bOk = pushBiffErrorOperand( rStrm.readuInt8() ); break;
1298 case BIFF_TOKID_BOOL: bOk = pushBiffBoolOperand( rStrm.readuInt8() ); break;
1299 case BIFF_TOKID_INT: bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
1300 case BIFF_TOKID_NUM: bOk = pushValueOperand( rStrm.readDouble() ); break;
1301 default: bOk = false;
1302 }
1303 }
1304 else
1305 {
1306 // classified tokens
1307 switch( nBaseId )
1308 {
1309 case BIFF_TOKID_ARRAY: bOk = importArrayToken( rStrm ); break;
1310 case BIFF_TOKID_FUNC: bOk = importFuncToken( rStrm ); break;
1311 case BIFF_TOKID_FUNCVAR: bOk = importFuncVarToken( rStrm ); break;
1312 case BIFF_TOKID_NAME: bOk = importNameToken( rStrm ); break;
1313 case BIFF_TOKID_REF: bOk = importRefToken( rStrm, false, false ); break;
1314 case BIFF_TOKID_AREA: bOk = importAreaToken( rStrm, false, false ); break;
1315 case BIFF_TOKID_MEMAREA: bOk = importMemAreaToken( rStrm, true ); break;
1316 case BIFF_TOKID_MEMERR: bOk = importMemAreaToken( rStrm, false ); break;
1317 case BIFF_TOKID_MEMNOMEM: bOk = importMemAreaToken( rStrm, false ); break;
1318 case BIFF_TOKID_MEMFUNC: bOk = importMemFuncToken( rStrm ); break;
1319 case BIFF_TOKID_REFERR: bOk = importRefToken( rStrm, true, false ); break;
1320 case BIFF_TOKID_AREAERR: bOk = importAreaToken( rStrm, true, false ); break;
1321 case BIFF_TOKID_REFN: bOk = importRefToken( rStrm, false, true ); break;
1322 case BIFF_TOKID_AREAN: bOk = importAreaToken( rStrm, false, true ); break;
1323 case BIFF_TOKID_MEMAREAN: bOk = importMemFuncToken( rStrm ); break;
1324 case BIFF_TOKID_MEMNOMEMN: bOk = importMemFuncToken( rStrm ); break;
1325 case BIFF_TOKID_NAMEX: bOk = importNameXToken( rStrm ); break;
1326 case BIFF_TOKID_REF3D: bOk = importRef3dToken( rStrm, false, bRelativeAsOffset ); break;
1327 case BIFF_TOKID_AREA3D: bOk = importArea3dToken( rStrm, false, bRelativeAsOffset ); break;
1328 case BIFF_TOKID_REFERR3D: bOk = importRef3dToken( rStrm, true, bRelativeAsOffset ); break;
1329 case BIFF_TOKID_AREAERR3D: bOk = importArea3dToken( rStrm, true, bRelativeAsOffset ); break;
1330 default: bOk = false;
1331 }
1332 }
1333 }
1334
1335 // build and finalize the token sequence
1336 ApiTokenSequence aFinalTokens;
1337 if( bOk && (rStrm.tell() == nFmlaEndPos) && (mnAddDataPos == nAddDataEndPos) )
1338 aFinalTokens = finalizeImport();
1339
1340 // seek behind token array
1341 if( (nFmlaSize >= 0) && (nAddDataSize >= 0) )
1342 rStrm.seek( nAddDataEndPos );
1343
1344 // return the final token sequence
1345 return aFinalTokens;
1346}
1347
1348// import token contents and create API formula token -------------------------
1349
1350bool OoxFormulaParserImpl::importAttrToken( SequenceInputStream& rStrm )
1351{
1352 bool bOk = true;
1354 nType = rStrm.readuChar();
1355 // equal flags in all BIFFs
1356 switch( nType )
1357 {
1358 case 0: // sometimes, tAttrSkip tokens miss the type flag
1360 case BIFF_TOK_ATTR_IF:
1361 case BIFF_TOK_ATTR_SKIP:
1364 rStrm.skip( 2 );
1365 break;
1367 rStrm.skip( 2 * rStrm.readuInt16() + 2 );
1368 break;
1369 case BIFF_TOK_ATTR_SUM:
1370 rStrm.skip( 2 );
1371 bOk = pushBiff12Function( BIFF_FUNC_SUM, 1 );
1372 break;
1375 bOk = importSpaceToken( rStrm );
1376 break;
1377 default:
1378 bOk = false;
1379 }
1380 return bOk;
1381}
1382
1383bool OoxFormulaParserImpl::importSpaceToken( SequenceInputStream& rStrm )
1384{
1385 // equal constants in BIFF and OOX
1387 nType = rStrm.readuChar();
1388 nCount = rStrm.readuChar();
1389 switch( nType )
1390 {
1392 appendLeadingSpaces( nCount, false );
1393 break;
1395 appendLeadingSpaces( nCount, true );
1396 break;
1398 appendOpeningSpaces( nCount, false );
1399 break;
1401 appendOpeningSpaces( nCount, true );
1402 break;
1404 appendClosingSpaces( nCount, false );
1405 break;
1407 appendClosingSpaces( nCount, true );
1408 break;
1409 }
1410 return true;
1411}
1412
1413bool OoxFormulaParserImpl::importTableToken( SequenceInputStream& rStrm )
1414{
1415 sal_uInt16 nFlags, nTableId, nCol1, nCol2;
1416 rStrm.skip( 3 );
1417 nFlags = rStrm.readuInt16();
1418 nTableId = rStrm.readuInt16();
1419 rStrm.skip( 2 );
1420 nCol1 = rStrm.readuInt16();
1421 nCol2 = rStrm.readuInt16();
1422 TableRef xTable = getTables().getTable( nTableId );
1423 sal_Int32 nTokenIndex = xTable ? xTable->getTokenIndex() : -1;
1424 if( nTokenIndex >= 0 )
1425 {
1426 sal_Int32 nWidth = xTable->getWidth();
1427 sal_Int32 nHeight = xTable->getHeight();
1428 sal_Int32 nStartCol = 0;
1429 sal_Int32 nEndCol = nWidth - 1;
1430 sal_Int32 nStartRow = 0;
1431 sal_Int32 nEndRow = nHeight - 1;
1432 bool bFixedStartRow = true;
1433 bool bFixedHeight = false;
1434
1435 bool bSingleCol = getFlag( nFlags, BIFF12_TOK_TABLE_COLUMN );
1436 bool bColRange = getFlag( nFlags, BIFF12_TOK_TABLE_COLRANGE );
1437 bool bValidRef = !bSingleCol || !bColRange;
1438 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - illegal combination of single column and column range" );
1439 if( bValidRef )
1440 {
1441 if( bSingleCol )
1442 nStartCol = nEndCol = nCol1;
1443 else if( bColRange )
1444 { nStartCol = nCol1; nEndCol = nCol2; }
1445 bValidRef = (nStartCol <= nEndCol) && (nEndCol < nWidth);
1446 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid column range" );
1447 }
1448
1449 if( bValidRef )
1450 {
1451 bool bAllRows = getFlag( nFlags, BIFF12_TOK_TABLE_ALL );
1452 bool bHeaderRows = getFlag( nFlags, BIFF12_TOK_TABLE_HEADERS );
1453 bool bDataRows = getFlag( nFlags, BIFF12_TOK_TABLE_DATA );
1454 bool bTotalsRows = getFlag( nFlags, BIFF12_TOK_TABLE_TOTALS );
1455 bool bThisRow = getFlag( nFlags, BIFF12_TOK_TABLE_THISROW );
1456
1457 sal_Int32 nStartDataRow = xTable->getHeaderRows();
1458 sal_Int32 nEndDataRow = nEndRow - xTable->getTotalsRows();
1459 bValidRef = (nStartRow <= nStartDataRow) && (nStartDataRow <= nEndDataRow) && (nEndDataRow <= nEndRow);
1460 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid data row range" );
1461 if( bValidRef )
1462 {
1463 if( bAllRows )
1464 {
1465 bValidRef = !bHeaderRows && !bDataRows && !bTotalsRows && !bThisRow;
1466 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#All] table token" );
1467 }
1468 else if( bHeaderRows )
1469 {
1470 bValidRef = !bTotalsRows && !bThisRow;
1471 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Headers] table token" );
1472 nEndRow = bDataRows ? nEndDataRow : (nStartDataRow - 1);
1473 bFixedHeight = !bDataRows;
1474 }
1475 else if( bDataRows )
1476 {
1477 bValidRef = !bThisRow;
1478 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Data] table token" );
1479 nStartRow = nStartDataRow;
1480 if( !bTotalsRows ) nEndRow = nEndDataRow;
1481 }
1482 else if( bTotalsRows )
1483 {
1484 bValidRef = !bThisRow;
1485 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Totals] table token" );
1486 nStartRow = nEndDataRow + 1;
1487 bFixedStartRow = false;
1488 bFixedHeight = !bDataRows;
1489 }
1490 else if( bThisRow )
1491 {
1492 nStartRow = nEndRow = maBaseAddr.Row() - xTable->getRange().aStart.Row();
1493 bFixedHeight = true;
1494 }
1495 else
1496 {
1497 // nothing is the same as [#Data]
1498 nStartRow = nStartDataRow;
1499 nEndRow = nEndDataRow;
1500 }
1501 }
1502 if( bValidRef )
1503 bValidRef = (0 <= nStartRow) && (nStartRow <= nEndRow) && (nEndRow < nHeight);
1504 }
1505 if( bValidRef )
1506 {
1507 // push single database area token, if table token refers to entire table
1508 if( (nStartCol == 0) && (nEndCol + 1 == nWidth) && (nStartRow == 0) && (nEndRow + 1 == nHeight) )
1509 return pushValueOperand( nTokenIndex, OPCODE_DBAREA );
1510 // create an OFFSET function call to refer to a subrange of the table
1511 const FunctionInfo* pRowsInfo = getFuncInfoFromBiff12FuncId( BIFF_FUNC_ROWS );
1512 const FunctionInfo* pColumnsInfo = getFuncInfoFromBiff12FuncId( BIFF_FUNC_COLUMNS );
1513 return
1514 pRowsInfo && pColumnsInfo &&
1515 pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1516 (bFixedStartRow ?
1517 pushValueOperandToken< double >( nStartRow ) :
1518 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1519 pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1520 pushValueOperandToken< double >( nHeight - nStartRow ) &&
1521 pushBinaryOperatorToken( OPCODE_SUB ))) &&
1522 pushValueOperandToken< double >( nStartCol ) &&
1523 (bFixedHeight ?
1524 pushValueOperandToken< double >( nEndRow - nStartRow + 1 ) :
1525 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1526 pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1527 (((nStartRow == 0) && (nEndRow + 1 == nHeight)) ||
1528 (pushValueOperandToken< double >( nHeight - (nEndRow - nStartRow + 1) ) &&
1529 pushBinaryOperatorToken( OPCODE_SUB ))))) &&
1530 (((nStartCol == 0) && (nEndCol + 1 == nWidth)) ?
1531 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1532 pushFunctionOperatorToken( *pColumnsInfo, 1 )) :
1533 pushValueOperandToken< double >( nEndCol - nStartCol + 1 )) &&
1534 pushBiff12Function( BIFF_FUNC_OFFSET, 5 );
1535 }
1536 }
1537 return pushBiffErrorOperand( BIFF_ERR_REF );
1538}
1539
1540bool OoxFormulaParserImpl::importArrayToken( SequenceInputStream& rStrm )
1541{
1542 rStrm.skip( 14 );
1543
1544 // start token array with opening brace and leading spaces
1545 pushOperand( OPCODE_ARRAY_OPEN );
1546 size_t nOpSize = popOperandSize();
1547 size_t nOldArraySize = getFormulaSize();
1548
1549 // read array size
1550 swapStreamPosition( rStrm );
1551 sal_Int32 nRows = rStrm.readInt32();
1552 sal_Int32 nCols = rStrm.readInt32();
1553 OSL_ENSURE( (nCols > 0) && (nRows > 0), "OoxFormulaParserImpl::importArrayToken - empty array" );
1554
1555 // read array values and build token array
1556 for( sal_Int32 nRow = 0; !rStrm.isEof() && (nRow < nRows); ++nRow )
1557 {
1558 if( nRow > 0 )
1559 appendRawToken( OPCODE_ARRAY_ROWSEP );
1560 for( sal_Int32 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
1561 {
1562 if( nCol > 0 )
1563 appendRawToken( OPCODE_ARRAY_COLSEP );
1564 switch( rStrm.readuInt8() )
1565 {
1567 appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
1568 break;
1570 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::readString( rStrm, false );
1571 break;
1573 appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
1574 break;
1576 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
1577 rStrm.skip( 3 );
1578 break;
1579 default:
1580 OSL_FAIL( "OoxFormulaParserImpl::importArrayToken - unknown data type" );
1581 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
1582 }
1583 }
1584 }
1585 swapStreamPosition( rStrm );
1586
1587 // close token array and set resulting operand size
1588 appendRawToken( OPCODE_ARRAY_CLOSE );
1589 pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
1590 return true;
1591}
1592
1593bool OoxFormulaParserImpl::importRefToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1594{
1595 BinSingleRef2d aRef;
1596 aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1597 return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1598}
1599
1600bool OoxFormulaParserImpl::importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1601{
1602 BinComplexRef2d aRef;
1603 aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1604 return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1605}
1606
1607bool OoxFormulaParserImpl::importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1608{
1609 LinkSheetRange aSheetRange = readSheetRange( rStrm );
1610 BinSingleRef2d aRef;
1611 aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1612 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1613}
1614
1615bool OoxFormulaParserImpl::importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1616{
1617 LinkSheetRange aSheetRange = readSheetRange( rStrm );
1618 BinComplexRef2d aRef;
1619 aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1620 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1621}
1622
1623bool OoxFormulaParserImpl::importMemAreaToken( SequenceInputStream& rStrm, bool bAddData )
1624{
1625 rStrm.skip( 6 );
1626 if( bAddData )
1627 skipMemAreaAddData( rStrm );
1628 return true;
1629}
1630
1631bool OoxFormulaParserImpl::importMemFuncToken( SequenceInputStream& rStrm )
1632{
1633 rStrm.skip( 2 );
1634 return true;
1635}
1636
1637bool OoxFormulaParserImpl::importNameToken( SequenceInputStream& rStrm )
1638{
1639 return pushBiff12Name( rStrm.readInt32() );
1640}
1641
1642bool OoxFormulaParserImpl::importNameXToken( SequenceInputStream& rStrm )
1643{
1644 sal_Int32 nRefId = rStrm.readInt16();
1645 sal_Int32 nNameId = rStrm.readInt32();
1646 return pushBiff12ExtName( nRefId, nNameId );
1647}
1648
1649bool OoxFormulaParserImpl::importFuncToken( SequenceInputStream& rStrm )
1650{
1651 sal_uInt16 nFuncId;
1652 nFuncId = rStrm.readuInt16();
1653 return pushBiff12Function( nFuncId );
1654}
1655
1656bool OoxFormulaParserImpl::importFuncVarToken( SequenceInputStream& rStrm )
1657{
1658 sal_uInt8 nParamCount;
1659 sal_uInt16 nFuncId;
1660 nParamCount = rStrm.readuChar();
1661 nFuncId = rStrm.readuInt16();
1662 return pushBiff12Function( nFuncId, nParamCount );
1663}
1664
1665bool OoxFormulaParserImpl::importExpToken( SequenceInputStream& rStrm )
1666{
1667 BinAddress aBaseAddr;
1668 aBaseAddr.mnRow = rStrm.readInt32();
1669 swapStreamPosition( rStrm );
1670 aBaseAddr.mnCol = rStrm.readInt32();
1671 swapStreamPosition( rStrm );
1672 return pushSpecialTokenOperand( aBaseAddr );
1673}
1674
1675LinkSheetRange OoxFormulaParserImpl::readSheetRange( SequenceInputStream& rStrm )
1676{
1677 return getExternalLinks().getSheetRange( rStrm.readInt16() );
1678}
1679
1680void OoxFormulaParserImpl::swapStreamPosition( SequenceInputStream& rStrm )
1681{
1682 sal_Int64 nRecPos = rStrm.tell();
1683 rStrm.seek( mnAddDataPos );
1684 mnAddDataPos = nRecPos;
1685}
1686
1687void OoxFormulaParserImpl::skipMemAreaAddData( SequenceInputStream& rStrm )
1688{
1689 swapStreamPosition( rStrm );
1690 rStrm.skip( 16 * rStrm.readInt32() );
1691 swapStreamPosition( rStrm );
1692}
1693
1694// convert BIN token and push API operand or operator -------------------------
1695
1696bool OoxFormulaParserImpl::pushBiff12Name( sal_Int32 nNameId )
1697{
1698 // one-based in BIFF12 formulas
1699 return pushDefinedNameOperand( getDefinedNames().getByIndex( nNameId - 1 ) );
1700}
1701
1702bool OoxFormulaParserImpl::pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId )
1703{
1704 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
1705 {
1706 if( pExtLink->getLinkType() == ExternalLinkType::Self )
1707 return pushBiff12Name( nNameId );
1708 // external name indexes are one-based in BIFF12
1709 ExternalNameRef xExtName = pExtLink->getNameByIndex( nNameId - 1 );
1710 return pushExternalNameOperand( xExtName, *pExtLink );
1711 }
1712 return pushBiffErrorOperand( BIFF_ERR_NAME );
1713}
1714
1715bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId )
1716{
1717 if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( nFuncId ) )
1718 if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
1719 return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
1720 return pushFunctionOperator( OPCODE_NONAME, 0 );
1721}
1722
1723bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
1724{
1725 if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
1726 nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
1727 if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( nFuncId ) )
1728 return pushFunctionOperator( *pFuncInfo, nParamCount );
1729 return pushFunctionOperator( OPCODE_NONAME, nParamCount );
1730}
1731
1732namespace {
1733
1736bool lclExtractRefId( sal_Int32& rnRefId, OUString& rRemainder, std::u16string_view aFormulaString )
1737{
1738 if( (aFormulaString.size() >= 4) && (aFormulaString[ 0 ] == '[') )
1739 {
1740 size_t nBracketClose = aFormulaString.find( ']', 1 );
1741 if( nBracketClose != std::u16string_view::npos && nBracketClose >= 2 )
1742 {
1743 rnRefId = o3tl::toInt32(aFormulaString.substr( 1, nBracketClose - 1 ));
1744 rRemainder = aFormulaString.substr( nBracketClose + 1 );
1745 return !rRemainder.isEmpty();
1746 }
1747 }
1748 return false;
1749}
1750
1751}
1752
1753FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
1754 FormulaProcessorBase( rHelper )
1755{
1756 mxImpl.reset( new OoxFormulaParserImpl( *this ) );
1757}
1758
1760{
1761}
1762
1763ApiTokenSequence FormulaParser::importFormula( const ScAddress& rBaseAddress, const OUString& rFormulaString ) const
1764{
1765 return mxImpl->importOoxFormula( rBaseAddress, rFormulaString );
1766}
1767
1769{
1770 return mxImpl->importBiff12Formula( rBaseAddress, eType, rStrm );
1771}
1772
1773OUString FormulaParser::importOleTargetLink( std::u16string_view aFormulaString )
1774{
1775 sal_Int32 nRefId = -1;
1776 OUString aRemainder;
1777 if( lclExtractRefId( nRefId, aRemainder, aFormulaString ) && (aRemainder.getLength() >= 3) &&
1778 (aRemainder[ 0 ] == '!') && (aRemainder[ 1 ] == '\'') && (aRemainder[ aRemainder.getLength() - 1 ] == '\'') )
1779 return mxImpl->resolveOleTarget( nRefId, false );
1780 return OUString();
1781}
1782
1784{
1785 OUString aTargetLink;
1786 sal_Int32 nFmlaSize = rStrm.readInt32();
1787 sal_Int64 nFmlaEndPos = rStrm.tell() + ::std::max< sal_Int32 >( nFmlaSize, 0 );
1788 if( (nFmlaSize == 7) && (rStrm.getRemaining() >= 7) )
1789 {
1790 sal_uInt8 nToken = rStrm.readuChar();
1791 sal_Int16 nRefId = rStrm.readInt16();
1792 rStrm.skip(4); //nNameId
1794 aTargetLink = mxImpl->resolveOleTarget( nRefId, true );
1795 }
1796 rStrm.seek( nFmlaEndPos );
1797 return aTargetLink;
1798}
1799
1800OUString FormulaParser::importMacroName( std::u16string_view aFormulaString )
1801{
1802 /* Valid macros are either sheet macros or VBA macros. OOXML and all BIFF
1803 documents store defined names for sheet macros, but OOXML documents do
1804 not store any defined name for VBA macros (while BIFF documents do).
1805 Sheet macros may be defined locally to a sheet, or globally to the
1806 document. As a result, all of the following macro specifiers are valid:
1807
1808 1) Macros located in the own document:
1809 [0]!MySheetMacro (global sheet macro 'MySheetMacro')
1810 Macro1!MyMacro (sheet-local sheet macro 'MyMacro')
1811 [0]!MyVBAProc (VBA macro 'MyVBAProc')
1812 [0]!Mod1.MyVBAProc (VBA macro 'MyVBAProc' from code module 'Mod1')
1813
1814 2) Macros from an external document:
1815 [2]!MySheetMacro (global external sheet macro 'MySheetMacro')
1816 [2]Macro1!MyMacro (sheet-local external sheet macro 'MyMacro')
1817 [2]!MyVBAProc (external VBA macro 'MyVBAProc')
1818 [2]!Mod1.MyVBAProc (external VBA macro from code module 'Mod1')
1819
1820 This implementation is only interested in VBA macros from the own
1821 document, ignoring the valid syntax 'Macro1!MyMacro' for sheet-local
1822 sheet macros.
1823 */
1824 OUString aRemainder(aFormulaString);
1825 if (aRemainder.indexOf('!') == -1)
1826 return aRemainder;
1827
1828 sal_Int32 nRefId = -1;
1829 if( lclExtractRefId( nRefId, aRemainder, aFormulaString ) && (aRemainder.getLength() > 1) && (aRemainder[ 0 ] == '!') )
1830 {
1831 /* In BIFF12 documents, the reference identifier is always the
1832 one-based index of the external link as it is in OOXML documents
1833 (it is not an index into the list of reference sheets as used in
1834 cell formulas). Index 0 is an implicit placeholder for the own
1835 document. In BIFF12 documents, the reference to the own document is
1836 stored explicitly, mostly at the top of the list, so index 1 may
1837 resolve to the own document too.
1838 Passing 'false' to getExternalLink() specifies to ignore the
1839 reference sheets list (if existing) and to access the list of
1840 external links directly. */
1841 const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, false ).get();
1842 OSL_ENSURE( pExtLink, "FormulaParser::importMacroName - missing link" );
1843 // do not accept macros in external documents (not supported)
1844 if( pExtLink && (pExtLink->getLinkType() == ExternalLinkType::Self) )
1845 {
1846 // ignore sheet macros (defined name for VBA macros may not exist, see above)
1847 OUString aMacroName = aRemainder.copy( 1 );
1848 const DefinedName* pDefName = getDefinedNames().getByModelName( aMacroName ).get();
1849 if( !pDefName || pDefName->isVBName() )
1850 return aMacroName;
1851 }
1852 }
1853 return OUString();
1854}
1855
1856} // namespace oox
1857
1858/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
OUString getAbsoluteUrl(const OUString &rUrl) const
A vector of formula tokens with additional convenience functions.
ApiTokenSequence toSequence() const
Converts to a sequence.
css::uno::Any & append(sal_Int32 nOpCode)
Appends a new token with the passed op-code, returns its data field.
void push_back(const ApiToken &rToken)
static double calcDoubleFromError(sal_uInt8 nErrorCode)
Converts the passed BIFF error to a double containing the respective Calc error code.
Definition: biffhelper.cxx:57
Base class for defined names and external names.
const OUString & getModelName() const
Returns the original name as imported from or exported to the file.
bool isVBName() const
Returns true, if this defined name is a reference to a VBA macro.
DefinedNameRef getByModelName(const OUString &rModelName, sal_Int16 nCalcSheet=-1) const
Returns a defined name by its model name.
ExternalLinkRef getExternalLink(sal_Int32 nRefId, bool bUseRefSheets=true) const
Returns the external link for the passed reference identifier.
A generic formula token array finalizer.
virtual const FunctionInfo * resolveBadFuncName(const OUString &rTokenData) const
Derived classed may try to find a function info struct from the passed string extracted from an OPCOD...
const ApiToken * skipParentheses(const ApiToken *pToken, const ApiToken *pTokenEnd) const
ApiTokenSequence finalizeTokenArray(const ApiTokenSequence &rTokens)
Finalizes and returns the passed token array.
FormulaFinalizer(const OpCodeProvider &rOpCodeProv)
const ApiToken * findParameters(ParameterPosVector &rParams, const ApiToken *pToken, const ApiToken *pTokenEnd) const
const FunctionInfo * getFunctionInfo(ApiToken &orFuncToken)
void appendRequiredParameters(const FunctionInfo &rFuncInfo, size_t nParamCount)
::std::vector< const ApiToken * > ParameterPosVector
void processTokens(const ApiToken *pToken, const ApiToken *pTokenEnd)
void appendEmptyParameter(const FunctionInfo &rFuncInfo, size_t nParam)
void appendCalcOnlyParameter(const FunctionInfo &rFuncInfo, size_t nParam, size_t nParamCount)
const ApiToken * getSingleToken(const ApiToken *pToken, const ApiToken *pTokenEnd) const
bool appendFinalToken(const ApiToken &rToken)
virtual OUString resolveDefinedName(sal_Int32 nTokenIndex) const
Derived classed may try to find the name of a defined name with the passed index extracted from an OP...
const FunctionInfo * getExternCallInfo(ApiToken &orFuncToken, const ApiToken &rECToken)
bool isEmptyParameter(const ApiToken *pToken, const ApiToken *pTokenEnd) const
const ApiToken * processParameters(const FunctionInfo &rFuncInfo, const ApiToken *pToken, const ApiToken *pTokenEnd)
ApiTokenVector maTokenStorage
True = special handling for tExp and tTbl tokens, false = exit with error.
virtual OUString resolveDefinedName(sal_Int32 nTokenIndex) const override
Derived classed may try to find the name of a defined name with the passed index extracted from an OP...
bool pushValueOperandToken(const Type &rValue)
bool pushDefinedNameOperand(const DefinedNameRef &rxDefName)
bool pushParenthesesOperatorToken(const WhiteSpaceVec *pOpeningSpaces=nullptr, const WhiteSpaceVec *pClosingSpaces=nullptr)
bool mb2dRefsAs3dRefs
True = relative row/column index is (signed) offset, false = explicit index.
::std::vector< WhiteSpace > WhiteSpaceVec
bool pushSpecialTokenOperand(const BinAddress &rBaseAddr)
Any & insertRawToken(sal_Int32 nOpCode, size_t nIndexFromEnd)
WhiteSpaceVec maLeadingSpaces
Stack with token sizes per operand.
std::vector< size_t > maOperandSizeStack
Indexes into maTokenStorage.
bool pushExternalFuncOperand(const FunctionInfo &rFuncInfo)
bool pushBoolOperand(bool bValue)
bool mbRelativeAsOffset
Base address for relative references.
static void appendSpaces(WhiteSpaceVec &orSpaces, sal_Int32 nCount, bool bLineFeed)
bool pushReferenceOperand(const BinSingleRef2d &rRef, bool bDeleted, bool bRelativeAsOffset)
bool pushOperandToken(sal_Int32 nOpCode, const WhiteSpaceVec *pSpaces=nullptr)
bool pushBinaryOperator(sal_Int32 nOpCode)
bool pushUnaryPostOperator(sal_Int32 nOpCode)
WhiteSpaceVec maClosingSpaces
List of whitespaces before opening parenthesis.
::std::pair< sal_Int32, bool > WhiteSpace
void appendOpeningSpaces(sal_Int32 nCount, bool bLineFeed)
bool pushExternalNameOperand(const ExternalNameRef &rxExtName, const ExternalLink &rExtLink)
void initializeImport(const ScAddress &rBaseAddress, FormulaType eType)
Initializes the formula parser before importing a formula.
ApiToken & getOperandToken(size_t nOpIndex, size_t nTokenIndex)
bool pushValueOperand(const Type &rValue)
virtual ApiTokenSequence importBiff12Formula(const ScAddress &rBaseAddress, FormulaType eType, SequenceInputStream &rStrm)
Imports and converts a BIFF12 token array from the passed stream.
bool pushUnaryPreOperatorToken(sal_Int32 nOpCode, const WhiteSpaceVec *pSpaces=nullptr)
bool pushValueOperand(const Type &rValue, sal_Int32 nOpCode)
void appendClosingSpaces(sal_Int32 nCount, bool bLineFeed)
const sal_Int32 mnMaxXlsCol
Maximum row index in own document.
bool pushErrorOperand(double fEncodedError)
bool pushUnaryPreOperator(sal_Int32 nOpCode)
bool pushDdeLinkOperand(const OUString &rDdeServer, const OUString &rDdeTopic, const OUString &rDdeItem)
const sal_Int32 mnMaxApiRow
Maximum column index in own document.
WhiteSpaceVec maOpeningSpaces
List of whitespaces before next token.
OUString resolveOleTarget(sal_Int32 nRefId, bool bUseRefSheets) const
Tries to resolve the passed ref-id to an OLE target URL.
bool pushEmbeddedRefOperand(const DefinedNameBase &rName, bool bPushBadToken)
bool pushFunctionOperatorToken(sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec *pLeadingSpaces=nullptr, const WhiteSpaceVec *pClosingSpaces=nullptr)
void convertReference2d(SingleReference &orApiRef, const BinSingleRef2d &rRef, bool bDeleted, bool bRelativeAsOffset) const
Any & appendRawToken(sal_Int32 nOpCode)
bool pushOperand(sal_Int32 nOpCode)
void convertReference3d(SingleReference &orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d &rRef, bool bDeleted, bool bRelativeAsOffset) const
bool pushUnaryPostOperatorToken(sal_Int32 nOpCode, const WhiteSpaceVec *pSpaces=nullptr)
ApiTokenSequence finalizeImport()
Finalizes the internal token storage after import.
bool mbSpecialTokens
True = convert all 2D references to 3D references in sheet specified by base address.
FormulaParserImpl(const FormulaParser &rParent)
bool pushParenthesesOperandToken(const WhiteSpaceVec *pClosingSpaces=nullptr)
const sal_Int32 mnMaxXlsRow
Maximum column index in imported document.
static void initReference3d(SingleReference &orApiRef, sal_Int32 nSheet, bool bSameSheet)
bool pushBiffErrorOperand(sal_uInt8 nErrorCode)
void pushOperandSize(size_t nSize)
size_t appendWhiteSpaceTokens(const WhiteSpaceVec *pSpaces)
ScAddress maBaseAddr
Maximum row index in imported document.
void convertReference(SingleReference &orApiRef, const BinSingleRef2d &rRef, bool bDeleted, bool bRelativeAsOffset) const
bool pushBinaryOperatorToken(sal_Int32 nOpCode, const WhiteSpaceVec *pSpaces=nullptr)
std::vector< size_t > maTokenIndexes
Raw unordered token storage.
void initReference2d(SingleReference &orApiRef) const
size_t insertWhiteSpaceTokens(const WhiteSpaceVec *pSpaces, size_t nIndexFromEnd)
bool pushFunctionOperator(sal_Int32 nOpCode, size_t nParamCount)
virtual ApiTokenSequence importOoxFormula(const ScAddress &rBaseAddress, const OUString &rFormulaString)
Converts an OOXML formula string.
size_t getOperandSize(size_t nOpIndex) const
bool pushBiffBoolOperand(sal_uInt8 nValue)
void appendLeadingSpaces(sal_Int32 nCount, bool bLineFeed)
virtual const FunctionInfo * resolveBadFuncName(const OUString &rTokenData) const override
Derived classed may try to find a function info struct from the passed string extracted from an OPCOD...
bool pushValueOperandToken(const Type &rValue, sal_Int32 nOpCode, const WhiteSpaceVec *pSpaces=nullptr)
Import formula parser for OOXML and BIFF filters.
virtual ~FormulaParser() override
ApiTokenSequence importFormula(const ScAddress &rBaseAddr, const OUString &rFormulaString) const
Converts an OOXML formula string.
OUString importMacroName(std::u16string_view aFormulaString)
Converts the passed formula to a macro name for a drawing shape.
::std::unique_ptr< FormulaParserImpl > mxImpl
OUString importOleTargetLink(std::u16string_view aFormulaString)
Converts the passed XML formula to an OLE link target.
Base class for import formula parsers and export formula compilers.
Iterator working on the mpParamInfos member of the FunctionInfo struct.
const FunctionInfo * getFuncInfoFromBiff12FuncId(sal_uInt16 nFuncId) const
Returns the function info for a BIFF12 function index, or 0 on error.
const FunctionInfo * getFuncInfoFromOoxFuncName(const OUString &rFuncName) const
Returns the function info for an OOXML function name, or 0 on error.
Contains indexes for a range of sheets in the spreadsheet document.
bool isExternal() const
Returns true, if the sheet range points to an external document.
sal_Int32 getDocLinkIndex() const
bool is3dRange() const
Returns true, if the sheet indexes are valid and different.
bool isSameSheet() const
Returns true, if the sheet indexes are valid and different.
Provides access to API op-codes for all available formula tokens and to function info structs for all...
const FunctionInfo * getFuncInfoFromApiToken(const ApiToken &rToken) const
Returns the function info for an API token, or 0 on error.
Helper class to provide access to global workbook data.
DefinedNamesBuffer & getDefinedNames() const
Returns the defined names read from the workbook globals.
::oox::core::FilterBase & getBaseFilter() const
Returns the base filter object (base class of all filters).
ExternalLinkBuffer & getExternalLinks() const
Returns the external links read from the external links substream.
int nCount
DocumentType eType
sal_Int16 nValue
sal_uInt8 mnMinParamCount
BIFF2-BIFF8 function identifier.
bool mbNeedExtRefs
Current stream position for additional data (tExp, tArray, tMemArea).
sal_Int64 mnAddDataPos
Wrapper for the API formula parser object.
ApiParserWrapper maApiParser
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
Type
void SvStream & rStrm
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
const sal_uInt8 BIFF_TOKID_MEMFUNC
Constant reference subexpression without result.
const sal_uInt8 BIFF_TOKID_LT
String concatenation operator.
Definition: formulabase.hxx:69
const sal_uInt8 BIFF_TOKID_LIST
Intersection operator.
Definition: formulabase.hxx:76
const sal_uInt16 BIFF_FUNC_EXTERNCALL
Function identifier of the OFFSET function.
css::sheet::FormulaToken ApiToken
const sal_uInt8 BIFF_TOK_ATTR_CHOOSE
Start of true condition in IF function.
const sal_uInt8 BIFF_TOKID_GE
Equal operator.
Definition: formulabase.hxx:72
const sal_uInt8 BIFF_TOKID_RANGE
List operator.
Definition: formulabase.hxx:77
const sal_uInt16 BIFF_FUNC_SUM
Function identifier of the IF function.
const sal_uInt8 BIFF_TOK_ATTR_SKIP
Jump array of CHOOSE function.
const sal_uInt8 BIFF_TOKID_REFN
Deleted 2D area reference.
const sal_uInt8 BIFF_TOKID_UMINUS
Unary plus.
Definition: formulabase.hxx:79
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR
Spaces before next token.
std::shared_ptr< ExternalName > ExternalNameRef
const sal_uInt16 BIFF_FUNC_COLUMNS
Function identifier of the ROWS function.
const sal_uInt16 BIFF12_TOK_TABLE_COLRANGE
Table reference: Single column.
const sal_uInt8 BIFF_TOKID_NAMEX
const sal_uInt16 BIFF_FUNC_TRUE
Function identifier of the SUM function.
const sal_uInt8 BIFF_TOKID_AREAERR
Deleted 2D cell reference.
const sal_uInt8 BIFF_TOKID_NE
Greater than operator.
Definition: formulabase.hxx:74
const sal_uInt8 BIFF_TOK_ATTR_VOLATILE
TRUE value of a tBool token.
const sal_uInt16 BIFF12_TOK_TABLE_DATA
Table reference: Special [#Headers] range.
const sal_uInt8 BIFF_TOKID_REF3D
External reference.
css::uno::Sequence< ApiToken > ApiTokenSequence
const sal_uInt8 BIFF_TOK_ATTR_ASSIGN
SUM function with one parameter.
const sal_uInt8 BIFF_TOKID_REFERR
Variable reference subexpression.
const sal_uInt16 BIFF12_TOK_TABLE_TOTALS
Table reference: Special [#Data] range.
const sal_uInt8 BIFF_TOKID_AREAN
Relative 2D cell reference (in names).
const sal_uInt8 BIFF_TOKID_ATTR
Natural language reference (NLR).
Definition: formulabase.hxx:85
const sal_uInt8 BIFF_TOKID_EXP
Placeholder for invalid token id.
Definition: formulabase.hxx:61
const sal_uInt8 BIFF_TOKID_ISECT
Not equal operator.
Definition: formulabase.hxx:75
const sal_uInt8 BIFF_ERR_NA
Definition: biffhelper.hxx:566
css::beans::Pair< css::table::CellAddress, sal_Bool > ApiSpecialTokenInfo
Contains the base address and type of a special token representing an array formula or a shared formu...
std::shared_ptr< Table > TableRef
Definition: tablebuffer.hxx:89
const sal_uInt8 BIFF_TOKID_SUB
Addition operator.
Definition: formulabase.hxx:64
const sal_uInt8 BIFF_TOKID_NAME
Function, variable number of arguments.
Definition: formulabase.hxx:98
FormulaType
Function identifier of the WEEKNUM function.
@ CondFormat
Shared formula definition.
@ Validation
Condition of a conditional format rule.
@ Array
Simple cell formula, or reference to a shared formula name.
@ SharedFormula
Array (matrix) formula.
const sal_uInt16 BIFF_FUNC_FLOOR
BIFF function id of the EXTERN.CALL function.
const sal_uInt8 BIFF_TOKID_INT
Boolean constant.
Definition: formulabase.hxx:90
const sal_uInt8 BIFF_TOKID_MEMNOMEM
Deleted reference subexpression.
const sal_uInt8 BIFF_TOKID_FUNCVAR
Function, fixed number of arguments.
Definition: formulabase.hxx:97
const sal_uInt16 BIFF12_TOK_TABLE_HEADERS
Table reference: Special [#All] range.
const sal_uInt8 BIFF_TOKID_MUL
Subtraction operator.
Definition: formulabase.hxx:65
const sal_uInt8 BIFF_TOK_ATTR_SPACE
BASIC style assignment.
const sal_uInt8 BIFF_TOKID_GT
Greater than or equal operator.
Definition: formulabase.hxx:73
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_CLOSE
Spaces before closing parenthesis.
const sal_uInt8 BIFF_TOK_ARRAY_DOUBLE
Deleted 3D area reference.
const sal_uInt8 BIFF_TOKID_AREAERR3D
Deleted 3D cell reference.
const sal_uInt8 BIFF_TOKID_REFERR3D
3D area reference.
const sal_uInt8 BIFF_TOKID_MEMAREAN
Relative 2D area reference (in names).
const sal_uInt8 BIFF_TOKID_AREA
2D cell reference.
const sal_uInt8 BIFF_TOK_ATTR_IFERROR
Leading spaces and volatile formula.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_VOLATILE
Spaces in formula representation.
const sal_uInt8 BIFF_TOKID_LE
Less than operator.
Definition: formulabase.hxx:70
const sal_uInt8 BIFF_TOKID_ERR
End of a sheet reference (BIFF2-BIFF4).
Definition: formulabase.hxx:88
const sal_uInt8 BIFF_TOKID_AREA3D
3D cell reference.
std::shared_ptr< DefinedName > DefinedNameRef
const sal_uInt8 BIFF_TOKID_EQ
Less than or equal operator.
Definition: formulabase.hxx:71
const sal_uInt8 BIFF_TOKID_CONCAT
Power operator.
Definition: formulabase.hxx:68
const sal_uInt8 BIFF_TOKID_PAREN
Percent sign.
Definition: formulabase.hxx:81
const sal_uInt8 BIFF_TOK_ARRAY_BOOL
String value in an array.
@ Library
Just for round-tripping (FIXME: Functionality not actually implemented after all.)
@ External
Link refers to the current sheet.
@ DDE
Link refers to an external add-in.
const sal_uInt8 BIFF_TOKID_PERCENT
Unary minus.
Definition: formulabase.hxx:80
const sal_uInt8 BIFF_TOKID_MISSARG
Parentheses.
Definition: formulabase.hxx:82
const sal_uInt8 BIFF_TOKCLASS_VAL
20-3F: Reference class tokens.
Definition: formulabase.hxx:51
const sal_uInt8 BIFF_TOKID_MEMERR
Constant reference subexpression.
const sal_uInt8 BIFF_TOKID_REF
Defined name.
Definition: formulabase.hxx:99
const sal_uInt8 BIFF_TOKID_FUNC
Array constant.
Definition: formulabase.hxx:96
const sal_uInt16 BIFF_FUNC_OFFSET
Function identifier of the COLUMNS function.
const sal_uInt16 BIFF12_TOK_TABLE_THISROW
Table reference: Special [#Totals] range.
const sal_uInt8 BIFF_TOKID_MASK
This bit must be null for a valid token identifier.
Definition: formulabase.hxx:58
const sal_uInt8 BIFF_TOK_ARRAY_ERROR
Boolean value in an array.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_BR_OPEN
Spaces before opening parenthesis.
const sal_uInt8 BIFF_ERR_NAME
Definition: biffhelper.hxx:564
const sal_uInt16 BIFF_FUNC_CEILING
Function identifier of the FLOOR function.
const sal_uInt16 BIFF_FUNC_FALSE
Function identifier of the TRUE function.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP
Start of condition in IFERROR function (BIFF12 only).
const sal_uInt16 BIFF_FUNC_IF
Maximum parameter count for BIFF2-BIFF8 files.
const sal_uInt8 BIFF_TOKID_UPLUS
Range operator.
Definition: formulabase.hxx:78
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_OPEN
Line breaks before next token.
const sal_uInt8 BIFF_TOKID_NLR
String constant.
Definition: formulabase.hxx:84
const sal_uInt8 BIFF_TOKID_MEMAREA
2D area reference.
const sal_uInt8 BIFF_TOKID_DIV
Multiplication operator.
Definition: formulabase.hxx:66
const sal_uInt16 BIFF12_TOK_TABLE_ALL
Table reference: Range of columns.
const sal_uInt8 BIFF_TOK_ATTR_SPACE_SP_CLOSE
Line breaks before opening parenthesis.
const sal_uInt8 BIFF_TOKID_ADD
Multiple operation reference.
Definition: formulabase.hxx:63
const sal_uInt8 BIFF_ERR_REF
Definition: biffhelper.hxx:563
const sal_uInt8 BIFF_TOKID_NUM
Integer constant.
Definition: formulabase.hxx:91
const sal_uInt8 BIFF_TOK_ATTR_IF
Volatile function.
const sal_uInt16 BIFF_FUNC_ROWS
Function identifier of the FALSE function.
const sal_uInt8 BIFF_TOKID_BOOL
Error constant.
Definition: formulabase.hxx:89
const sal_uInt8 BIFF_TOK_ARRAY_STRING
Double value in an array.
const sal_uInt8 BIFF_TOK_BOOL_FALSE
Error code in an array.
const sal_uInt8 BIFF_TOKCLASS_MASK
Maximum size of a token array.
Definition: formulabase.hxx:48
const sal_uInt8 BIFF_TOKID_STR
Missing argument.
Definition: formulabase.hxx:83
const sal_uInt8 BIFF_TOK_FUNCVAR_COUNTMASK
User prompt for macro commands.
const sal_uInt16 BIFF_TOK_FUNCVAR_CMD
Spaces before formula (BIFF3).
const sal_uInt8 BIFF_TOK_ATTR_SUM
Skip tokens.
const sal_uInt8 BIFF_TOKID_POWER
Division operator.
Definition: formulabase.hxx:67
const sal_uInt16 BIFF_FUNC_WEEKNUM
Function identifier of the HYPERLINK function.
const sal_uInt8 BIFF_TOKID_MEMNOMEMN
Reference subexpression (in names).
const sal_uInt16 BIFF12_TOK_TABLE_COLUMN
True = row is relative.
const sal_uInt8 BIFF_TOKID_ARRAY
Floating-point constant.
Definition: formulabase.hxx:95
const sal_uInt8 BIFF_TOKCLASS_NONE
Definition: formulabase.hxx:49
void setFlag(Type &ornBitField, Type nMask, bool bSet=true)
bool getFlag(Type nBitField, Type nMask)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
OpCode
DefTokenId nToken
Definition: qproform.cxx:397
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
Contains all API op-codes needed to build formulas with tokens.
sal_Int32 OPCODE_MISSING
Op-code for common value operands.
sal_Int32 OPCODE_NAME
Spaces between other formula tokens.
sal_Int32 OPCODE_ARRAY_OPEN
Function parameter separator.
sal_Int32 OPCODE_DDE
Natural language reference.
sal_Int32 OPCODE_SEP
Closing parenthesis.
sal_Int32 OPCODE_CLOSE
Opening parenthesis.
sal_Int32 OPCODE_BAD
Macro function call.
sal_Int32 OPCODE_OPEN
Function style #NAME? error.
sal_Int32 OPCODE_MACRO
DDE link function.
sal_Int32 OPCODE_NONAME
Bad token (unknown name, formula error).
sal_Int32 OPCODE_SPACES
Placeholder for a missing function parameter.
sal_Int32 OPCODE_ARRAY_CLOSE
Opening brace for constant arrays.
sal_Int32 OPCODE_EXTERNAL
Internal: function name unknown to mapper.
sal_Int32 OPCODE_PUSH
External function call (e.g. add-ins).
A 2D cell address struct for binary filters.
A 2D formula cell range reference struct with relative flags.
BinSingleRef2d maRef2
Start (top-left) cell address.
A 2D formula cell reference struct with relative flags.
bool mbRowRel
True = relative column reference.
sal_Int32 mnRow
Column index.
Represents information for a spreadsheet function.
sal_uInt16 mnBiffFuncId
BIFF12 function identifier.
OUString maExtProgName
Expected macro name in EXTERN.CALL function.
sal_Int32 mnApiOpCode
The external library this function is part of.
OUString maOoxFuncName
ODF function name.
sal_uInt16 mnBiff12FuncId
API function opcode.
unsigned char sal_uInt8