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