merge the formfield patch from ooo-build
[ooovba.git] / oox / source / xls / formulaparser.cxx
blobf0ff482e58286575e75092596321418ba7e8db21
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: formulaparser.cxx,v $
10 * $Revision: 1.5.20.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/formulaparser.hxx"
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/sheet/ComplexReference.hpp>
34 #include <com/sun/star/sheet/ExternalReference.hpp>
35 #include <com/sun/star/sheet/FormulaToken.hpp>
36 #include <com/sun/star/sheet/ReferenceFlags.hpp>
37 #include <com/sun/star/sheet/SingleReference.hpp>
38 #include "properties.hxx"
39 #include "oox/helper/recordinputstream.hxx"
40 #include "oox/core/filterbase.hxx"
41 #include "oox/xls/addressconverter.hxx"
42 #include "oox/xls/biffinputstream.hxx"
43 #include "oox/xls/defnamesbuffer.hxx"
44 #include "oox/xls/externallinkbuffer.hxx"
45 #include "oox/xls/tablebuffer.hxx"
46 #include "oox/xls/worksheethelper.hxx"
48 using ::rtl::OUString;
49 using ::com::sun::star::uno::Any;
50 using ::com::sun::star::uno::Reference;
51 using ::com::sun::star::uno::Sequence;
52 using ::com::sun::star::uno::Exception;
53 using ::com::sun::star::uno::UNO_QUERY;
54 using ::com::sun::star::uno::UNO_QUERY_THROW;
55 using ::com::sun::star::table::CellAddress;
56 using ::com::sun::star::table::CellRangeAddress;
57 using ::com::sun::star::sheet::ComplexReference;
58 using ::com::sun::star::sheet::ExternalReference;
59 using ::com::sun::star::sheet::SingleReference;
60 using ::com::sun::star::sheet::XFormulaParser;
61 using namespace ::com::sun::star::sheet::ReferenceFlags;
63 namespace oox {
64 namespace xls {
66 // ============================================================================
68 namespace {
70 sal_uInt16 lclReadFmlaSize( BiffInputStream& rStrm, BiffType eBiff, const sal_uInt16* pnFmlaSize )
72 return pnFmlaSize ? *pnFmlaSize : ((eBiff == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16());
75 } // namespace
77 // formula finalizer ==========================================================
79 FormulaFinalizer::FormulaFinalizer( const OpCodeProvider& rOpCodeProv ) :
80 OpCodeProvider( rOpCodeProv ),
81 ApiOpCodes( getOpCodes() )
83 maTokens.reserve( 0x2000 );
86 ApiTokenSequence FormulaFinalizer::finalizeTokenArray( const ApiTokenSequence& rTokens )
88 maTokens.clear();
89 if( rTokens.hasElements() )
91 const ApiToken* pToken = rTokens.getConstArray();
92 processTokens( pToken, pToken + rTokens.getLength() );
94 return ContainerHelper::vectorToSequence( maTokens );
97 const FunctionInfo* FormulaFinalizer::resolveBadFuncName( const OUString& ) const
99 return 0;
102 OUString FormulaFinalizer::resolveDefinedName( sal_Int32 ) const
104 return OUString();
107 const FunctionInfo* FormulaFinalizer::getFunctionInfo( ApiToken& orFuncToken )
109 // first, try to find a regular function info from token op-code
110 if( const FunctionInfo* pRegFuncInfo = getFuncInfoFromApiToken( orFuncToken ) )
111 return pRegFuncInfo;
113 // try to recognize a function from an external library
114 if( (orFuncToken.OpCode == OPCODE_BAD) && orFuncToken.Data.has< OUString >() )
116 // virtual call to resolveBadFuncName()
117 if( const FunctionInfo* pLibFuncInfo = resolveBadFuncName( orFuncToken.Data.get< OUString >() ) )
119 // write function op-code to the OPCODE_BAD token
120 orFuncToken.OpCode = pLibFuncInfo->mnApiOpCode;
121 // if it is an external function, insert programmatic function name
122 if( (orFuncToken.OpCode == OPCODE_EXTERNAL) && (pLibFuncInfo->maExtProgName.getLength() > 0) )
123 orFuncToken.Data <<= pLibFuncInfo->maExtProgName;
124 else
125 orFuncToken.Data.clear(); // clear string from OPCODE_BAD
126 return pLibFuncInfo;
130 // no success - return null
131 return 0;
135 const FunctionInfo* FormulaFinalizer::getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken )
137 // try to resolve the passed token to a supported sheet function
138 if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
140 orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
141 // programmatic add-in function name
142 if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
143 orFuncToken.Data <<= pFuncInfo->maExtProgName;
144 // name of unsupported function, convert to OPCODE_BAD to preserve the name
145 else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && (pFuncInfo->maOoxFuncName.getLength() > 0) )
146 orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
147 return pFuncInfo;
150 // macro call or unknown function name, move data to function token
151 if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
152 orFuncToken = rECToken;
154 // defined name used as function call, convert to OPCODE_BAD to preserve the name
155 if( (rECToken.OpCode == OPCODE_NAME) && rECToken.Data.has< sal_Int32 >() )
157 OUString aDefName = resolveDefinedName( rECToken.Data.get< sal_Int32 >() );
158 if( aDefName.getLength() > 0 )
160 orFuncToken.OpCode = OPCODE_BAD;
161 orFuncToken.Data <<= aDefName;
165 return 0;
168 void FormulaFinalizer::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
170 while( pToken < pTokenEnd )
172 // push the current token into the vector
173 bool bValid = appendFinalToken( *pToken );
174 // try to process a function
175 if( const FunctionInfo* pFuncInfo = bValid ? getFunctionInfo( maTokens.back() ) : 0 )
176 pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
177 // otherwise, go to next token
178 else
179 ++pToken;
183 const ApiToken* FormulaFinalizer::processParameters(
184 const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
186 // remember position of the token containing the function op-code
187 size_t nFuncNameIdx = maTokens.size() - 1;
189 // process a function, if an OPCODE_OPEN token is following
190 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::processParameters - OPCODE_OPEN expected" );
191 if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
193 // append the OPCODE_OPEN token to the vector
194 maTokens.append( OPCODE_OPEN );
196 // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
197 ParameterPosVector aParams;
198 pToken = findParameters( aParams, pToken, pTokenEnd );
199 OSL_ENSURE( aParams.size() >= 2, "FormulaFinalizer::processParameters - missing tokens" );
200 size_t nParamCount = aParams.size() - 1;
202 if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
204 /* Empty pair of parentheses -> function call without parameters,
205 process parameter, there might be spaces between parentheses. */
206 processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
208 else
210 const FunctionInfo* pRealFuncInfo = &rFuncInfo;
211 ParameterPosVector::const_iterator aPosIt = aParams.begin();
213 /* Preprocess EXTERN.CALL functions. The actual function name is
214 contained as reference to a defined name in the first (hidden)
215 parameter. */
216 if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
218 ApiToken& rFuncToken = maTokens[ nFuncNameIdx ];
219 rFuncToken.OpCode = OPCODE_NONAME;
221 // try to initialize function token from first parameter
222 if( const ApiToken* pECToken = getSingleToken( *aPosIt + 1, *(aPosIt + 1) ) )
223 if( const FunctionInfo* pECFuncInfo = getExternCallInfo( rFuncToken, *pECToken ) )
224 pRealFuncInfo = pECFuncInfo;
226 /* On success (something has been inserted into rFuncToken),
227 skip the first parameter. */
228 if( rFuncToken.OpCode != OPCODE_NONAME )
230 --nParamCount;
231 ++aPosIt;
235 // process all parameters
236 FunctionParamInfoIterator aParamInfoIt( *pRealFuncInfo );
237 size_t nLastValidSize = maTokens.size();
238 size_t nLastValidCount = 0;
239 for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aParamInfoIt )
241 // add embedded Calc-only parameters
242 if( aParamInfoIt.isCalcOnlyParam() )
244 appendCalcOnlyParameter( *pRealFuncInfo, nParam );
245 while( aParamInfoIt.isCalcOnlyParam() ) ++aParamInfoIt;
248 const ApiToken* pParamBegin = *aPosIt + 1;
249 const ApiToken* pParamEnd = *(aPosIt + 1);
250 bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
252 if( !aParamInfoIt.isExcelOnlyParam() )
254 // replace empty second and third parameter in IF function with zeros
255 if( (pRealFuncInfo->mnOobFuncId == OOBIN_FUNC_IF) && ((nParam == 1) || (nParam == 2)) && bIsEmpty )
257 maTokens.append< double >( OPCODE_PUSH, 0.0 );
258 bIsEmpty = false;
260 else
262 // process all tokens of the parameter
263 processTokens( pParamBegin, pParamEnd );
265 // append parameter separator token
266 maTokens.append( OPCODE_SEP );
269 /* #84453# Update size of new token sequence with valid parameters
270 to be able to remove trailing optional empty parameters. */
271 if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
273 nLastValidSize = maTokens.size();
274 nLastValidCount = nParam + 1;
278 // #84453# remove trailing optional empty parameters
279 maTokens.resize( nLastValidSize );
281 // add trailing Calc-only parameters
282 if( aParamInfoIt.isCalcOnlyParam() )
283 appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
285 // add optional parameters that are required in Calc
286 appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
288 // remove last parameter separator token
289 if( maTokens.back().OpCode == OPCODE_SEP )
290 maTokens.pop_back();
293 /* Append the OPCODE_CLOSE token to the vector, but only if there is
294 no OPCODE_BAD token at the end, this token already contains the
295 trailing closing parentheses. */
296 if( (pTokenEnd - 1)->OpCode != OPCODE_BAD )
297 maTokens.append( OPCODE_CLOSE );
300 /* Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
301 if no matching add-in function was found. */
302 ApiToken& rFuncNameToken = maTokens[ nFuncNameIdx ];
303 if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
304 rFuncNameToken.OpCode = OPCODE_NONAME;
306 return pToken;
309 bool FormulaFinalizer::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
311 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
312 if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
313 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
314 return pToken == pTokenEnd;
317 const ApiToken* FormulaFinalizer::getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
319 const ApiToken* pSingleToken = 0;
320 // skip leading whitespace tokens
321 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
322 // remember first non-whitespace token
323 if( pToken < pTokenEnd ) pSingleToken = pToken++;
324 // skip trailing whitespace tokens
325 while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
326 // return null, if other non-whitespace tokens follow
327 return (pToken == pTokenEnd) ? pSingleToken : 0;
330 const ApiToken* FormulaFinalizer::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
332 // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
333 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
334 ++pToken;
335 while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
337 if( pToken->OpCode == OPCODE_OPEN )
338 pToken = skipParentheses( pToken, pTokenEnd );
339 else
340 ++pToken;
342 // skip the OPCODE_CLOSE token
343 OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
344 return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
347 const ApiToken* FormulaFinalizer::findParameters( ParameterPosVector& rParams,
348 const ApiToken* pToken, const ApiToken* pTokenEnd ) const
350 // push position of OPCODE_OPEN
351 OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::findParameters - OPCODE_OPEN expected" );
352 rParams.push_back( pToken++ );
354 // find positions of parameter separators
355 while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
357 if( pToken->OpCode == OPCODE_OPEN )
358 pToken = skipParentheses( pToken, pTokenEnd );
359 else if( pToken->OpCode == OPCODE_SEP )
360 rParams.push_back( pToken++ );
361 else
362 ++pToken;
365 // push position of OPCODE_CLOSE
366 OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaFinalizer::findParameters - OPCODE_CLOSE expected" );
367 rParams.push_back( pToken );
368 return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
371 void FormulaFinalizer::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
373 (void)nParam; // prevent 'unused' warning
374 switch( rFuncInfo.mnOobFuncId )
376 case OOBIN_FUNC_FLOOR:
377 case OOBIN_FUNC_CEILING:
378 OSL_ENSURE( nParam == 2, "FormulaFinalizer::appendCalcOnlyParameter - unexpected parameter index" );
379 maTokens.append< double >( OPCODE_PUSH, 1.0 );
380 maTokens.append( OPCODE_SEP );
381 break;
385 void FormulaFinalizer::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
387 switch( rFuncInfo.mnOobFuncId )
389 case OOBIN_FUNC_WEEKNUM:
390 if( nParamCount == 1 )
392 maTokens.append< double >( OPCODE_PUSH, 1.0 );
393 maTokens.append( OPCODE_SEP );
395 break;
399 bool FormulaFinalizer::appendFinalToken( const ApiToken& rToken )
401 // replace OPCODE_MACRO without macro name with #NAME? error code
402 bool bValid = (rToken.OpCode != OPCODE_MACRO) || rToken.Data.hasValue();
403 if( bValid )
405 maTokens.push_back( rToken );
407 else
409 maTokens.append( OPCODE_ARRAY_OPEN );
410 maTokens.append( OPCODE_PUSH, BiffHelper::calcDoubleFromError( BIFF_ERR_NAME ) );
411 maTokens.append( OPCODE_ARRAY_CLOSE );
413 return bValid;
416 // parser implementation base =================================================
418 class FormulaParserImpl : public FormulaFinalizer, public WorkbookHelper
420 public:
421 explicit FormulaParserImpl( const FormulaParser& rParent );
423 /** Converts an XML formula string. */
424 virtual void importOoxFormula(
425 FormulaContext& rContext,
426 const OUString& rFormulaString );
428 /** Imports and converts a OOBIN token array from the passed stream. */
429 virtual void importOobFormula(
430 FormulaContext& rContext,
431 RecordInputStream& rStrm );
433 /** Imports and converts a BIFF token array from the passed stream. */
434 virtual void importBiffFormula(
435 FormulaContext& rContext,
436 BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
438 /** Finalizes the passed token array after import (e.g. adjusts function
439 parameters) and sets the formula using the passed context. */
440 void setFormula(
441 FormulaContext& rContext,
442 const ApiTokenSequence& rTokens );
444 /** Tries to resolve the passed ref-id to an OLE target URL. */
445 OUString resolveOleTarget( sal_Int32 nRefId ) const;
447 protected:
448 typedef ::std::pair< sal_Int32, bool > WhiteSpace;
449 typedef ::std::vector< WhiteSpace > WhiteSpaceVec;
451 /** Sets the current formula context used for import. */
452 inline FormulaContext& getFormulaContext() const { return *mpContext; }
454 /** Sets the current formula context used for import. */
455 void initializeImport( FormulaContext& rContext );
456 /** Finalizes the passed token array after import. */
457 void finalizeImport( const ApiTokenSequence& rTokens );
458 /** Finalizes the internal token storage after import. */
459 void finalizeImport();
461 /** Inserts a shared formula using the current formula context and passed base address. */
462 void setSharedFormula( const BinAddress& rBaseAddr );
464 // token array ------------------------------------------------------------
466 bool resetSpaces();
467 static void appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed );
468 void appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed );
469 void appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed );
470 void appendClosingSpaces( sal_Int32 nCount, bool bLineFeed );
472 size_t getFormulaSize() const;
473 Any& appendRawToken( sal_Int32 nOpCode );
474 Any& insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd );
475 size_t appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces );
476 size_t insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd );
478 size_t getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const;
479 void pushOperandSize( size_t nSize );
480 size_t popOperandSize();
482 ApiToken& getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex );
483 void removeOperand( size_t nOpCountFromEnd, size_t nOpIndex );
484 void removeLastOperands( size_t nOpCountFromEnd );
486 bool pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
487 bool pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
488 template< typename Type >
489 bool pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
490 template< typename Type >
491 inline bool pushValueOperandToken( const Type& rValue, const WhiteSpaceVec* pSpaces = 0 )
492 { return pushValueOperandToken( rValue, OPCODE_PUSH, pSpaces ); }
493 bool pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
494 bool pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
495 bool pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
496 bool pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
497 bool pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
498 bool pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
499 bool pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
501 bool pushOperand( sal_Int32 nOpCode );
502 bool pushAnyOperand( const Any& rAny, sal_Int32 nOpCode );
503 template< typename Type >
504 bool pushValueOperand( const Type& rValue, sal_Int32 nOpCode );
505 template< typename Type >
506 inline bool pushValueOperand( const Type& rValue )
507 { return pushValueOperand( rValue, OPCODE_PUSH ); }
508 bool pushBoolOperand( bool bValue );
509 bool pushErrorOperand( double fEncodedError );
510 bool pushBiffBoolOperand( sal_uInt8 nValue );
511 bool pushBiffErrorOperand( sal_uInt8 nErrorCode );
512 bool pushParenthesesOperand();
513 bool pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
514 bool pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
515 template< typename Type >
516 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef );
517 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
518 bool pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
519 bool pushNlrOperand( const BinSingleRef2d& rRef );
520 bool pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken );
521 bool pushDefinedNameOperand( const DefinedNameRef& rxDefName );
522 bool pushExternalFuncOperand( const FunctionInfo& rFuncInfo );
523 bool pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem );
524 bool pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink );
526 bool pushUnaryPreOperator( sal_Int32 nOpCode );
527 bool pushUnaryPostOperator( sal_Int32 nOpCode );
528 bool pushBinaryOperator( sal_Int32 nOpCode );
529 bool pushParenthesesOperator();
530 bool pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount );
531 bool pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount );
533 private:
534 // reference conversion ---------------------------------------------------
536 void initReference2d( SingleReference& orApiRef ) const;
537 void initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet ) const;
538 void convertColRow( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bRelativeAsOffset ) const;
539 void convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
540 void convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
541 void convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
542 void convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
543 void convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
544 void convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
546 private:
547 // finalize token sequence ------------------------------------------------
549 virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
550 virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
552 protected:
553 const sal_Int32 mnMaxApiCol; /// Maximum column index in own document.
554 const sal_Int32 mnMaxApiRow; /// Maximum row index in own document.
555 const sal_Int32 mnMaxXlsCol; /// Maximum column index in imported document.
556 const sal_Int32 mnMaxXlsRow; /// Maximum row index in imported document.
558 private:
559 typedef ::std::vector< size_t > SizeTypeVector;
561 ApiTokenVector maTokenStorage; /// Raw unordered token storage.
562 SizeTypeVector maTokenIndexes; /// Indexes into maTokenStorage.
563 SizeTypeVector maOperandSizeStack; /// Stack with token sizes per operand.
564 WhiteSpaceVec maLeadingSpaces; /// List of whitespaces before next token.
565 WhiteSpaceVec maOpeningSpaces; /// List of whitespaces before opening parenthesis.
566 WhiteSpaceVec maClosingSpaces; /// List of whitespaces before closing parenthesis.
567 FormulaContext* mpContext; /// Current formula context.
570 // ----------------------------------------------------------------------------
572 FormulaParserImpl::FormulaParserImpl( const FormulaParser& rParent ) :
573 FormulaFinalizer( rParent ),
574 WorkbookHelper( rParent ),
575 mnMaxApiCol( rParent.getAddressConverter().getMaxApiAddress().Column ),
576 mnMaxApiRow( rParent.getAddressConverter().getMaxApiAddress().Row ),
577 mnMaxXlsCol( rParent.getAddressConverter().getMaxXlsAddress().Column ),
578 mnMaxXlsRow( rParent.getAddressConverter().getMaxXlsAddress().Row ),
579 mpContext( 0 )
581 // reserve enough space to make resize(), push_back() etc. cheap
582 maTokenStorage.reserve( 0x2000 );
583 maTokenIndexes.reserve( 0x2000 );
584 maOperandSizeStack.reserve( 256 );
585 maLeadingSpaces.reserve( 256 );
586 maOpeningSpaces.reserve( 256 );
587 maClosingSpaces.reserve( 256 );
590 void FormulaParserImpl::importOoxFormula( FormulaContext&, const OUString& )
592 OSL_ENSURE( false, "FormulaParserImpl::importOoxFormula - not implemented" );
595 void FormulaParserImpl::importOobFormula( FormulaContext&, RecordInputStream& )
597 OSL_ENSURE( false, "FormulaParserImpl::importOobFormula - not implemented" );
600 void FormulaParserImpl::importBiffFormula( FormulaContext&, BiffInputStream&, const sal_uInt16* )
602 OSL_ENSURE( false, "FormulaParserImpl::importBiffFormula - not implemented" );
605 void FormulaParserImpl::setFormula( FormulaContext& rContext, const ApiTokenSequence& rTokens )
607 initializeImport( rContext );
608 finalizeImport( rTokens );
611 OUString FormulaParserImpl::resolveOleTarget( sal_Int32 nRefId ) const
613 const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
614 OSL_ENSURE( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE), "FormulaParserImpl::resolveOleTarget - missing or wrong link" );
615 if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE) )
616 return getBaseFilter().getAbsoluteUrl( pExtLink->getTargetUrl() );
617 return OUString();
620 void FormulaParserImpl::initializeImport( FormulaContext& rContext )
622 maTokenStorage.clear();
623 maTokenIndexes.clear();
624 maOperandSizeStack.clear();
625 mpContext = &rContext;
628 void FormulaParserImpl::finalizeImport( const ApiTokenSequence& rTokens )
630 ApiTokenSequence aFinalTokens = finalizeTokenArray( rTokens );
631 if( aFinalTokens.hasElements() )
632 mpContext->setTokens( aFinalTokens );
635 void FormulaParserImpl::finalizeImport()
637 ApiTokenSequence aTokens( static_cast< sal_Int32 >( maTokenIndexes.size() ) );
638 if( aTokens.hasElements() )
640 ApiToken* pToken = aTokens.getArray();
641 for( SizeTypeVector::const_iterator aIt = maTokenIndexes.begin(), aEnd = maTokenIndexes.end(); aIt != aEnd; ++aIt, ++pToken )
642 *pToken = maTokenStorage[ *aIt ];
644 finalizeImport( aTokens );
647 void FormulaParserImpl::setSharedFormula( const BinAddress& rBaseAddr )
649 CellAddress aApiBaseAddr;
650 if( getAddressConverter().convertToCellAddress( aApiBaseAddr, rBaseAddr, mpContext->getBaseAddress().Sheet, false ) )
651 mpContext->setSharedFormula( aApiBaseAddr );
654 // token array ----------------------------------------------------------------
656 bool FormulaParserImpl::resetSpaces()
658 maLeadingSpaces.clear();
659 maOpeningSpaces.clear();
660 maClosingSpaces.clear();
661 return true;
664 void FormulaParserImpl::appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed )
666 OSL_ENSURE( nCount >= 0, "FormulaParserImpl::appendSpaces - negative count" );
667 if( nCount > 0 )
668 orSpaces.push_back( WhiteSpace( nCount, bLineFeed ) );
671 void FormulaParserImpl::appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed )
673 appendSpaces( maLeadingSpaces, nCount, bLineFeed );
676 void FormulaParserImpl::appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed )
678 appendSpaces( maOpeningSpaces, nCount, bLineFeed );
681 void FormulaParserImpl::appendClosingSpaces( sal_Int32 nCount, bool bLineFeed )
683 appendSpaces( maClosingSpaces, nCount, bLineFeed );
686 size_t FormulaParserImpl::getFormulaSize() const
688 return maTokenIndexes.size();
691 Any& FormulaParserImpl::appendRawToken( sal_Int32 nOpCode )
693 maTokenIndexes.push_back( maTokenStorage.size() );
694 return maTokenStorage.append( nOpCode );
697 Any& FormulaParserImpl::insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd )
699 maTokenIndexes.insert( maTokenIndexes.end() - nIndexFromEnd, maTokenStorage.size() );
700 return maTokenStorage.append( nOpCode );
703 size_t FormulaParserImpl::appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces )
705 if( pSpaces && !pSpaces->empty() )
706 for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
707 appendRawToken( OPCODE_SPACES ) <<= aIt->first;
708 return pSpaces ? pSpaces->size() : 0;
711 size_t FormulaParserImpl::insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd )
713 if( pSpaces && !pSpaces->empty() )
714 for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
715 insertRawToken( OPCODE_SPACES, nIndexFromEnd ) <<= aIt->first;
716 return pSpaces ? pSpaces->size() : 0;
719 size_t FormulaParserImpl::getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const
721 OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
722 "FormulaParserImpl::getOperandSize - invalid parameters" );
723 return maOperandSizeStack[ maOperandSizeStack.size() - nOpCountFromEnd + nOpIndex ];
726 void FormulaParserImpl::pushOperandSize( size_t nSize )
728 maOperandSizeStack.push_back( nSize );
731 size_t FormulaParserImpl::popOperandSize()
733 OSL_ENSURE( !maOperandSizeStack.empty(), "FormulaParserImpl::popOperandSize - invalid call" );
734 size_t nOpSize = maOperandSizeStack.back();
735 maOperandSizeStack.pop_back();
736 return nOpSize;
739 ApiToken& FormulaParserImpl::getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex )
741 OSL_ENSURE( getOperandSize( nOpCountFromEnd, nOpIndex ) > nTokenIndex,
742 "FormulaParserImpl::getOperandToken - invalid parameters" );
743 SizeTypeVector::const_iterator aIndexIt = maTokenIndexes.end();
744 for( SizeTypeVector::const_iterator aEnd = maOperandSizeStack.end(), aIt = aEnd - nOpCountFromEnd + nOpIndex; aIt != aEnd; ++aIt )
745 aIndexIt -= *aIt;
746 return maTokenStorage[ *(aIndexIt + nTokenIndex) ];
749 void FormulaParserImpl::removeOperand( size_t nOpCountFromEnd, size_t nOpIndex )
751 OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
752 "FormulaParserImpl::removeOperand - invalid parameters" );
753 // remove indexes into token storage, but do not touch storage itself
754 SizeTypeVector::iterator aSizeEnd = maOperandSizeStack.end();
755 SizeTypeVector::iterator aSizeIt = aSizeEnd - nOpCountFromEnd + nOpIndex;
756 size_t nRemainingSize = 0;
757 for( SizeTypeVector::iterator aIt = aSizeIt + 1; aIt != aSizeEnd; ++aIt )
758 nRemainingSize += *aIt;
759 maTokenIndexes.erase( maTokenIndexes.end() - nRemainingSize - *aSizeIt, maTokenIndexes.end() - nRemainingSize );
760 maOperandSizeStack.erase( aSizeIt );
763 void FormulaParserImpl::removeLastOperands( size_t nOpCountFromEnd )
765 for( size_t nOpIndex = 0; nOpIndex < nOpCountFromEnd; ++nOpIndex )
766 removeOperand( 1, 0 );
769 bool FormulaParserImpl::pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
771 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
772 appendRawToken( nOpCode );
773 pushOperandSize( nSpacesSize + 1 );
774 return true;
777 bool FormulaParserImpl::pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
779 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
780 appendRawToken( nOpCode ) = rAny;
781 pushOperandSize( nSpacesSize + 1 );
782 return true;
785 template< typename Type >
786 bool FormulaParserImpl::pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
788 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
789 appendRawToken( nOpCode ) <<= rValue;
790 pushOperandSize( nSpacesSize + 1 );
791 return true;
794 bool FormulaParserImpl::pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
796 size_t nSpacesSize = appendWhiteSpaceTokens( pOpeningSpaces );
797 appendRawToken( OPCODE_OPEN );
798 nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
799 appendRawToken( OPCODE_CLOSE );
800 pushOperandSize( nSpacesSize + 2 );
801 return true;
804 bool FormulaParserImpl::pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
806 bool bOk = maOperandSizeStack.size() >= 1;
807 if( bOk )
809 size_t nOpSize = popOperandSize();
810 size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOpSize );
811 insertRawToken( nOpCode, nOpSize );
812 pushOperandSize( nOpSize + nSpacesSize + 1 );
814 return bOk;
817 bool FormulaParserImpl::pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
819 bool bOk = maOperandSizeStack.size() >= 1;
820 if( bOk )
822 size_t nOpSize = popOperandSize();
823 size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
824 appendRawToken( nOpCode );
825 pushOperandSize( nOpSize + nSpacesSize + 1 );
827 return bOk;
830 bool FormulaParserImpl::pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
832 bool bOk = maOperandSizeStack.size() >= 2;
833 if( bOk )
835 size_t nOp2Size = popOperandSize();
836 size_t nOp1Size = popOperandSize();
837 size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOp2Size );
838 insertRawToken( nOpCode, nOp2Size );
839 pushOperandSize( nOp1Size + nSpacesSize + 1 + nOp2Size );
841 return bOk;
844 bool FormulaParserImpl::pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
846 bool bOk = maOperandSizeStack.size() >= 1;
847 if( bOk )
849 size_t nOpSize = popOperandSize();
850 size_t nSpacesSize = insertWhiteSpaceTokens( pOpeningSpaces, nOpSize );
851 insertRawToken( OPCODE_OPEN, nOpSize );
852 nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
853 appendRawToken( OPCODE_CLOSE );
854 pushOperandSize( nOpSize + nSpacesSize + 2 );
856 return bOk;
859 bool FormulaParserImpl::pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
861 /* #i70925# if there are not enough tokens available on token stack, do
862 not exit with error, but reduce parameter count. */
863 nParamCount = ::std::min( maOperandSizeStack.size(), nParamCount );
865 // convert all parameters on stack to a single operand separated with OPCODE_SEP
866 bool bOk = true;
867 for( size_t nParam = 1; bOk && (nParam < nParamCount); ++nParam )
868 bOk = pushBinaryOperatorToken( OPCODE_SEP );
870 // add function parentheses and function name
871 return bOk &&
872 ((nParamCount > 0) ? pushParenthesesOperatorToken( 0, pClosingSpaces ) : pushParenthesesOperandToken( 0, pClosingSpaces )) &&
873 pushUnaryPreOperatorToken( nOpCode, pLeadingSpaces );
876 bool FormulaParserImpl::pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
878 bool bOk = pushFunctionOperatorToken( rFuncInfo.mnApiOpCode, nParamCount, pLeadingSpaces, pClosingSpaces );
879 if( bOk )
881 // create an external add-in call for the passed built-in function
882 if( (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) && (rFuncInfo.maExtProgName.getLength() > 0) )
883 getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maExtProgName;
884 // create a bad token with unsupported function name
885 else if( (rFuncInfo.mnApiOpCode == OPCODE_BAD) && (rFuncInfo.maOoxFuncName.getLength() > 0) )
886 getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maOoxFuncName;
888 return bOk;
891 bool FormulaParserImpl::pushOperand( sal_Int32 nOpCode )
893 return pushOperandToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
896 bool FormulaParserImpl::pushAnyOperand( const Any& rAny, sal_Int32 nOpCode )
898 return pushAnyOperandToken( rAny, nOpCode, &maLeadingSpaces ) && resetSpaces();
901 template< typename Type >
902 bool FormulaParserImpl::pushValueOperand( const Type& rValue, sal_Int32 nOpCode )
904 return pushValueOperandToken( rValue, nOpCode, &maLeadingSpaces ) && resetSpaces();
907 bool FormulaParserImpl::pushBoolOperand( bool bValue )
909 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( bValue ? OOBIN_FUNC_TRUE : OOBIN_FUNC_FALSE ) )
910 return pushFunctionOperator( pFuncInfo->mnApiOpCode, 0 );
911 return pushValueOperand< double >( bValue ? 1.0 : 0.0 );
914 bool FormulaParserImpl::pushErrorOperand( double fEncodedError )
916 // HACK: enclose all error codes into an 1x1 matrix
917 // start token array with opening brace and leading spaces
918 pushOperand( OPCODE_ARRAY_OPEN );
919 size_t nOpSize = popOperandSize();
920 size_t nOldArraySize = maTokenIndexes.size();
921 // push a double containing the Calc error code
922 appendRawToken( OPCODE_PUSH ) <<= fEncodedError;
923 // close token array and set resulting operand size
924 appendRawToken( OPCODE_ARRAY_CLOSE );
925 pushOperandSize( nOpSize + maTokenIndexes.size() - nOldArraySize );
926 return true;
929 bool FormulaParserImpl::pushBiffBoolOperand( sal_uInt8 nValue )
931 return pushBoolOperand( nValue != BIFF_TOK_BOOL_FALSE );
934 bool FormulaParserImpl::pushBiffErrorOperand( sal_uInt8 nErrorCode )
936 return pushErrorOperand( BiffHelper::calcDoubleFromError( nErrorCode ) );
939 bool FormulaParserImpl::pushParenthesesOperand()
941 return pushParenthesesOperandToken( &maOpeningSpaces, &maClosingSpaces ) && resetSpaces();
944 bool FormulaParserImpl::pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
946 SingleReference aApiRef;
947 convertReference2d( aApiRef, rRef, bDeleted, bRelativeAsOffset );
948 return pushValueOperand( aApiRef );
951 bool FormulaParserImpl::pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
953 ComplexReference aApiRef;
954 convertReference2d( aApiRef, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
955 return pushValueOperand( aApiRef );
958 template< typename Type >
959 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef )
961 if( rSheetRange.isExternal() )
963 ExternalReference aApiExtRef;
964 aApiExtRef.Index = rSheetRange.getDocLinkIndex();
965 aApiExtRef.Reference <<= rApiRef;
966 return pushValueOperand( aApiExtRef );
968 return pushValueOperand( rApiRef );
971 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
973 if( rSheetRange.is3dRange() )
975 // single-cell-range over several sheets, needs to create a ComplexReference
976 ComplexReference aApiRef;
977 convertReference3d( aApiRef, rSheetRange, rRef, rRef, bDeleted, bRelativeAsOffset );
978 return pushReferenceOperand( rSheetRange, aApiRef );
980 SingleReference aApiRef;
981 convertReference3d( aApiRef, rSheetRange.getFirstSheet(), rSheetRange.isSameSheet(), rRef, bDeleted, bRelativeAsOffset );
982 return pushReferenceOperand( rSheetRange, aApiRef );
985 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
987 ComplexReference aApiRef;
988 convertReference3d( aApiRef, rSheetRange, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
989 return pushReferenceOperand( rSheetRange, aApiRef );
992 bool FormulaParserImpl::pushNlrOperand( const BinSingleRef2d& rRef )
994 SingleReference aApiRef;
995 convertReference2d( aApiRef, rRef, false, false );
996 return pushValueOperand( aApiRef, OPCODE_NLR );
999 bool FormulaParserImpl::pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken )
1001 Any aRefAny = rName.getReference( mpContext->getBaseAddress() );
1002 if( aRefAny.hasValue() )
1003 return pushAnyOperand( aRefAny, OPCODE_PUSH );
1004 if( bPushBadToken && (rName.getModelName().getLength() > 0) && (rName.getModelName()[ 0 ] >= ' ') )
1005 return pushValueOperand( rName.getModelName(), OPCODE_BAD );
1006 return pushBiffErrorOperand( BIFF_ERR_NAME );
1009 bool FormulaParserImpl::pushDefinedNameOperand( const DefinedNameRef& rxDefName )
1011 if( !rxDefName || (rxDefName->getModelName().getLength() == 0) )
1012 return pushBiffErrorOperand( BIFF_ERR_NAME );
1013 if( rxDefName->isMacroFunction() )
1014 return pushValueOperand( rxDefName->getModelName(), OPCODE_MACRO );
1015 if( rxDefName->getTokenIndex() >= 0 )
1016 return pushValueOperand( rxDefName->getTokenIndex(), OPCODE_NAME );
1017 return pushEmbeddedRefOperand( *rxDefName, true );
1020 bool FormulaParserImpl::pushExternalFuncOperand( const FunctionInfo& rFuncInfo )
1022 return (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) ?
1023 pushValueOperand( rFuncInfo.maExtProgName, OPCODE_EXTERNAL ) :
1024 pushOperand( rFuncInfo.mnApiOpCode );
1027 bool FormulaParserImpl::pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem )
1029 // create the function call DDE("server";"topic";"item")
1030 return
1031 pushValueOperandToken( rDdeServer ) &&
1032 pushValueOperandToken( rDdeTopic ) &&
1033 pushValueOperandToken( rDdeItem ) &&
1034 pushFunctionOperator( OPCODE_DDE, 3 );
1037 bool FormulaParserImpl::pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink )
1039 if( rxExtName.get() ) switch( rExtLink.getLinkType() )
1041 case LINKTYPE_INTERNAL:
1042 case LINKTYPE_EXTERNAL:
1043 return pushEmbeddedRefOperand( *rxExtName, false );
1045 case LINKTYPE_ANALYSIS:
1046 // TODO: need support for localized addin function names
1047 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
1048 return pushExternalFuncOperand( *pFuncInfo );
1049 break;
1051 case LINKTYPE_LIBRARY:
1052 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
1053 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == rExtLink.getFuncLibraryType()) )
1054 return pushExternalFuncOperand( *pFuncInfo );
1055 break;
1057 case LINKTYPE_DDE:
1059 OUString aDdeServer, aDdeTopic, aDdeItem;
1060 if( rxExtName->getDdeLinkData( aDdeServer, aDdeTopic, aDdeItem ) )
1061 return pushDdeLinkOperand( aDdeServer, aDdeTopic, aDdeItem );
1063 break;
1065 default:
1066 OSL_ENSURE( rExtLink.getLinkType() != LINKTYPE_SELF, "FormulaParserImpl::pushExternalNameOperand - invalid call" );
1068 return pushBiffErrorOperand( BIFF_ERR_NAME );
1071 bool FormulaParserImpl::pushUnaryPreOperator( sal_Int32 nOpCode )
1073 return pushUnaryPreOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1076 bool FormulaParserImpl::pushUnaryPostOperator( sal_Int32 nOpCode )
1078 return pushUnaryPostOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1081 bool FormulaParserImpl::pushBinaryOperator( sal_Int32 nOpCode )
1083 return pushBinaryOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1086 bool FormulaParserImpl::pushParenthesesOperator()
1088 return pushParenthesesOperatorToken( &maOpeningSpaces, &maClosingSpaces ) && resetSpaces();
1091 bool FormulaParserImpl::pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount )
1093 return pushFunctionOperatorToken( nOpCode, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1096 bool FormulaParserImpl::pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount )
1098 return pushFunctionOperatorToken( rFuncInfo, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1101 // reference conversion -------------------------------------------------------
1103 void FormulaParserImpl::initReference2d( SingleReference& orApiRef ) const
1105 if( mpContext->is2dRefsAs3dRefs() )
1107 initReference3d( orApiRef, mpContext->getBaseAddress().Sheet, false );
1109 else
1111 orApiRef.Flags = SHEET_RELATIVE;
1112 // #i10184# absolute sheet index needed for relative references in shared formulas
1113 orApiRef.Sheet = mpContext->getBaseAddress().Sheet;
1114 orApiRef.RelativeSheet = 0;
1118 void FormulaParserImpl::initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet ) const
1120 orApiRef.Flags = SHEET_3D;
1121 if( nSheet < 0 )
1123 orApiRef.Sheet = 0;
1124 orApiRef.Flags |= SHEET_DELETED;
1126 else if( bSameSheet )
1128 OSL_ENSURE( nSheet == 0, "FormulaParserImpl::initReference3d - invalid sheet index" );
1129 orApiRef.Flags |= SHEET_RELATIVE;
1130 orApiRef.RelativeSheet = 0;
1132 else
1134 orApiRef.Sheet = nSheet;
1138 void FormulaParserImpl::convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1140 if( bDeleted )
1142 orApiRef.Column = 0;
1143 orApiRef.Row = 0;
1144 // no explicit information about whether row or column is deleted
1145 orApiRef.Flags |= COLUMN_DELETED | ROW_DELETED;
1147 else
1149 // column/row indexes and flags
1150 setFlag( orApiRef.Flags, COLUMN_RELATIVE, rRef.mbColRel );
1151 setFlag( orApiRef.Flags, ROW_RELATIVE, rRef.mbRowRel );
1152 (rRef.mbColRel ? orApiRef.RelativeColumn : orApiRef.Column) = rRef.mnCol;
1153 (rRef.mbRowRel ? orApiRef.RelativeRow : orApiRef.Row) = rRef.mnRow;
1154 // convert absolute indexes to relative offsets used in API
1155 if( !bRelativeAsOffset )
1157 if( rRef.mbColRel )
1158 orApiRef.RelativeColumn -= mpContext->getBaseAddress().Column;
1159 if( rRef.mbRowRel )
1160 orApiRef.RelativeRow -= mpContext->getBaseAddress().Row;
1165 void FormulaParserImpl::convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1167 convertReference( orApiRef.Reference1, rRef1, bDeleted, bRelativeAsOffset );
1168 convertReference( orApiRef.Reference2, rRef2, bDeleted, bRelativeAsOffset );
1169 /* Handle references to complete rows or columns (e.g. $1:$2 or C:D),
1170 need to expand or shrink to limits of own document. */
1171 if( !bDeleted && !rRef1.mbColRel && !rRef2.mbColRel && (orApiRef.Reference1.Column == 0) && (orApiRef.Reference2.Column == mnMaxXlsCol) )
1172 orApiRef.Reference2.Column = mnMaxApiCol;
1173 if( !bDeleted && !rRef1.mbRowRel && !rRef2.mbRowRel && (orApiRef.Reference1.Row == 0) && (orApiRef.Reference2.Row == mnMaxXlsRow) )
1174 orApiRef.Reference2.Row = mnMaxApiRow;
1177 void FormulaParserImpl::convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1179 initReference2d( orApiRef );
1180 convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1183 void FormulaParserImpl::convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1185 initReference2d( orApiRef.Reference1 );
1186 initReference2d( orApiRef.Reference2 );
1187 convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1188 // remove sheet name from second part of reference
1189 setFlag( orApiRef.Reference2.Flags, SHEET_3D, false );
1192 void FormulaParserImpl::convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1194 initReference3d( orApiRef, nSheet, bSameSheet );
1195 convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1198 void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1200 bool bSameSheet = rSheetRange.isSameSheet();
1201 initReference3d( orApiRef.Reference1, rSheetRange.getFirstSheet(), bSameSheet );
1202 initReference3d( orApiRef.Reference2, rSheetRange.getLastSheet(), bSameSheet );
1203 convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1204 // remove sheet name from second part of reference
1205 setFlag( orApiRef.Reference2.Flags, SHEET_3D, rSheetRange.is3dRange() );
1208 // finalize token sequence ----------------------------------------------------
1210 const FunctionInfo* FormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
1212 /* Try to parse calls to library functions. The format of such a function
1213 call is "[n]!funcname", n>0 being the link identifier of the function
1214 library spreadsheet file. */
1215 sal_Int32 nBracketOpen = rTokenData.indexOf( '[' );
1216 sal_Int32 nBracketClose = rTokenData.indexOf( ']' );
1217 sal_Int32 nExclamation = rTokenData.indexOf( '!' );
1218 if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < rTokenData.getLength()) )
1220 sal_Int32 nRefId = rTokenData.copy( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ).toInt32();
1221 const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
1222 if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_LIBRARY) )
1224 OUString aFuncName = rTokenData.copy( nExclamation + 1 ).toAsciiUpperCase();
1225 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName ) )
1226 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
1227 return pFuncInfo;
1230 return 0;
1233 OUString FormulaParserImpl::resolveDefinedName( sal_Int32 nTokenIndex ) const
1235 if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
1236 return pDefName->getCalcName();
1237 return OUString();
1240 // OOX parser implementation ==================================================
1242 class OoxFormulaParserImpl : public FormulaParserImpl
1244 public:
1245 explicit OoxFormulaParserImpl( const FormulaParser& rParent );
1247 virtual void importOoxFormula(
1248 FormulaContext& rContext,
1249 const OUString& rFormulaString );
1251 virtual void importOobFormula(
1252 FormulaContext& rContext,
1253 RecordInputStream& rStrm );
1255 private:
1256 // import token contents and create API formula token ---------------------
1258 bool importAttrToken( RecordInputStream& rStrm );
1259 bool importSpaceToken( RecordInputStream& rStrm );
1260 bool importTableToken( RecordInputStream& rStrm );
1261 bool importArrayToken( RecordInputStream& rStrm );
1262 bool importRefToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1263 bool importAreaToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1264 bool importRef3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1265 bool importArea3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1266 bool importMemAreaToken( RecordInputStream& rStrm, bool bAddData );
1267 bool importMemFuncToken( RecordInputStream& rStrm );
1268 bool importNameToken( RecordInputStream& rStrm );
1269 bool importNameXToken( RecordInputStream& rStrm );
1270 bool importFuncToken( RecordInputStream& rStrm );
1271 bool importFuncVarToken( RecordInputStream& rStrm );
1272 bool importExpToken( RecordInputStream& rStrm );
1274 LinkSheetRange readSheetRange( RecordInputStream& rStrm );
1276 void swapStreamPosition( RecordInputStream& rStrm );
1277 void skipMemAreaAddData( RecordInputStream& rStrm );
1279 // convert BIN token and push API operand or operator ---------------------
1281 bool pushOobName( sal_Int32 nNameId );
1282 bool pushOobExtName( sal_Int32 nRefId, sal_Int32 nNameId );
1283 bool pushOobFunction( sal_uInt16 nFuncId );
1284 bool pushOobFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
1286 private:
1287 ApiParserWrapper maApiParser; /// Wrapper for the API formula parser object.
1288 sal_Int64 mnAddDataPos; /// Current stream position for additional data (tExp, tArray, tMemArea).
1289 bool mbNeedExtRefs; /// True = parser needs initialization of external reference info.
1292 // ----------------------------------------------------------------------------
1294 OoxFormulaParserImpl::OoxFormulaParserImpl( const FormulaParser& rParent ) :
1295 FormulaParserImpl( rParent ),
1296 maApiParser( rParent.getDocumentFactory(), rParent ),
1297 mnAddDataPos( 0 ),
1298 mbNeedExtRefs( true )
1302 void OoxFormulaParserImpl::importOoxFormula( FormulaContext& rContext, const OUString& rFormulaString )
1304 if( mbNeedExtRefs )
1306 maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
1307 mbNeedExtRefs = false;
1309 initializeImport( rContext );
1310 finalizeImport( maApiParser.parseFormula( rFormulaString, rContext.getBaseAddress() ) );
1313 void OoxFormulaParserImpl::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm )
1315 initializeImport( rContext );
1317 sal_Int32 nFmlaSize = rStrm.readInt32();
1318 sal_Int64 nFmlaPos = rStrm.tell();
1319 sal_Int64 nFmlaEndPos = nFmlaPos + nFmlaSize;
1321 rStrm.seek( nFmlaEndPos );
1322 sal_Int32 nAddDataSize = rStrm.readInt32();
1323 mnAddDataPos = rStrm.tell();
1324 sal_Int64 nAddDataEndPos = mnAddDataPos + nAddDataSize;
1325 rStrm.seek( nFmlaPos );
1327 bool bOk = (nFmlaSize >= 0) && (nAddDataSize >= 0);
1328 bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
1330 while( bOk && !rStrm.isEof() && (rStrm.tell() < nFmlaEndPos) )
1332 sal_uInt8 nTokenId;
1333 rStrm >> nTokenId;
1334 sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
1335 sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
1337 if( nTokenClass == BIFF_TOKCLASS_NONE )
1339 // base tokens
1340 switch( nBaseId )
1342 case BIFF_TOKID_EXP: bOk = importExpToken( rStrm ); break;
1343 case BIFF_TOKID_ADD: bOk = pushBinaryOperator( OPCODE_ADD ); break;
1344 case BIFF_TOKID_SUB: bOk = pushBinaryOperator( OPCODE_SUB ); break;
1345 case BIFF_TOKID_MUL: bOk = pushBinaryOperator( OPCODE_MULT ); break;
1346 case BIFF_TOKID_DIV: bOk = pushBinaryOperator( OPCODE_DIV ); break;
1347 case BIFF_TOKID_POWER: bOk = pushBinaryOperator( OPCODE_POWER ); break;
1348 case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( OPCODE_CONCAT ); break;
1349 case BIFF_TOKID_LT: bOk = pushBinaryOperator( OPCODE_LESS ); break;
1350 case BIFF_TOKID_LE: bOk = pushBinaryOperator( OPCODE_LESS_EQUAL ); break;
1351 case BIFF_TOKID_EQ: bOk = pushBinaryOperator( OPCODE_EQUAL ); break;
1352 case BIFF_TOKID_GE: bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL ); break;
1353 case BIFF_TOKID_GT: bOk = pushBinaryOperator( OPCODE_GREATER ); break;
1354 case BIFF_TOKID_NE: bOk = pushBinaryOperator( OPCODE_NOT_EQUAL ); break;
1355 case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( OPCODE_INTERSECT ); break;
1356 case BIFF_TOKID_LIST: bOk = pushBinaryOperator( OPCODE_LIST ); break;
1357 case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( OPCODE_RANGE ); break;
1358 case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN ); break;
1359 case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN ); break;
1360 case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( OPCODE_PERCENT ); break;
1361 case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
1362 case BIFF_TOKID_MISSARG: bOk = pushOperand( OPCODE_MISSING ); break;
1363 case BIFF_TOKID_STR: bOk = pushValueOperand( rStrm.readString( false ) ); break;
1364 case BIFF_TOKID_NLR: bOk = importTableToken( rStrm ); break;
1365 case BIFF_TOKID_ATTR: bOk = importAttrToken( rStrm ); break;
1366 case BIFF_TOKID_ERR: bOk = pushBiffErrorOperand( rStrm.readuInt8() ); break;
1367 case BIFF_TOKID_BOOL: bOk = pushBiffBoolOperand( rStrm.readuInt8() ); break;
1368 case BIFF_TOKID_INT: bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
1369 case BIFF_TOKID_NUM: bOk = pushValueOperand( rStrm.readDouble() ); break;
1370 default: bOk = false;
1373 else
1375 // classified tokens
1376 switch( nBaseId )
1378 case BIFF_TOKID_ARRAY: bOk = importArrayToken( rStrm ); break;
1379 case BIFF_TOKID_FUNC: bOk = importFuncToken( rStrm ); break;
1380 case BIFF_TOKID_FUNCVAR: bOk = importFuncVarToken( rStrm ); break;
1381 case BIFF_TOKID_NAME: bOk = importNameToken( rStrm ); break;
1382 case BIFF_TOKID_REF: bOk = importRefToken( rStrm, false, false ); break;
1383 case BIFF_TOKID_AREA: bOk = importAreaToken( rStrm, false, false ); break;
1384 case BIFF_TOKID_MEMAREA: bOk = importMemAreaToken( rStrm, true ); break;
1385 case BIFF_TOKID_MEMERR: bOk = importMemAreaToken( rStrm, false ); break;
1386 case BIFF_TOKID_MEMNOMEM: bOk = importMemAreaToken( rStrm, false ); break;
1387 case BIFF_TOKID_MEMFUNC: bOk = importMemFuncToken( rStrm ); break;
1388 case BIFF_TOKID_REFERR: bOk = importRefToken( rStrm, true, false ); break;
1389 case BIFF_TOKID_AREAERR: bOk = importAreaToken( rStrm, true, false ); break;
1390 case BIFF_TOKID_REFN: bOk = importRefToken( rStrm, false, true ); break;
1391 case BIFF_TOKID_AREAN: bOk = importAreaToken( rStrm, false, true ); break;
1392 case BIFF_TOKID_MEMAREAN: bOk = importMemFuncToken( rStrm ); break;
1393 case BIFF_TOKID_MEMNOMEMN: bOk = importMemFuncToken( rStrm ); break;
1394 case BIFF_TOKID_NAMEX: bOk = importNameXToken( rStrm ); break;
1395 case BIFF_TOKID_REF3D: bOk = importRef3dToken( rStrm, false, bRelativeAsOffset ); break;
1396 case BIFF_TOKID_AREA3D: bOk = importArea3dToken( rStrm, false, bRelativeAsOffset ); break;
1397 case BIFF_TOKID_REFERR3D: bOk = importRef3dToken( rStrm, true, bRelativeAsOffset ); break;
1398 case BIFF_TOKID_AREAERR3D: bOk = importArea3dToken( rStrm, true, bRelativeAsOffset ); break;
1399 default: bOk = false;
1404 // build and finalize the token sequence
1405 if( bOk && (rStrm.tell() == nFmlaEndPos) && (mnAddDataPos == nAddDataEndPos) )
1406 finalizeImport();
1408 // seek behind token array
1409 if( (nFmlaSize >= 0) && (nAddDataSize >= 0) )
1410 rStrm.seek( nAddDataEndPos );
1413 // import token contents and create API formula token -------------------------
1415 bool OoxFormulaParserImpl::importAttrToken( RecordInputStream& rStrm )
1417 bool bOk = true;
1418 sal_uInt8 nType;
1419 rStrm >> nType;
1420 // equal flags in BIFF and OOBIN
1421 switch( nType )
1423 case 0: // sometimes, tAttrSkip tokens miss the type flag
1424 case OOBIN_TOK_ATTR_VOLATILE:
1425 case OOBIN_TOK_ATTR_IF:
1426 case OOBIN_TOK_ATTR_SKIP:
1427 case OOBIN_TOK_ATTR_ASSIGN:
1428 case OOBIN_TOK_ATTR_IFERROR:
1429 rStrm.skip( 2 );
1430 break;
1431 case OOBIN_TOK_ATTR_CHOOSE:
1432 rStrm.skip( 2 * rStrm.readuInt16() + 2 );
1433 break;
1434 case OOBIN_TOK_ATTR_SUM:
1435 rStrm.skip( 2 );
1436 bOk = pushOobFunction( OOBIN_FUNC_SUM, 1 );
1437 break;
1438 case OOBIN_TOK_ATTR_SPACE:
1439 case OOBIN_TOK_ATTR_SPACE_VOLATILE:
1440 bOk = importSpaceToken( rStrm );
1441 break;
1442 default:
1443 bOk = false;
1445 return bOk;
1448 bool OoxFormulaParserImpl::importSpaceToken( RecordInputStream& rStrm )
1450 // equal constants in BIFF and OOX
1451 sal_uInt8 nType, nCount;
1452 rStrm >> nType >> nCount;
1453 switch( nType )
1455 case BIFF_TOK_ATTR_SPACE_SP:
1456 appendLeadingSpaces( nCount, false );
1457 break;
1458 case BIFF_TOK_ATTR_SPACE_BR:
1459 appendLeadingSpaces( nCount, true );
1460 break;
1461 case BIFF_TOK_ATTR_SPACE_SP_OPEN:
1462 appendOpeningSpaces( nCount, false );
1463 break;
1464 case BIFF_TOK_ATTR_SPACE_BR_OPEN:
1465 appendOpeningSpaces( nCount, true );
1466 break;
1467 case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
1468 appendClosingSpaces( nCount, false );
1469 break;
1470 case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
1471 appendClosingSpaces( nCount, true );
1472 break;
1474 return true;
1477 bool OoxFormulaParserImpl::importTableToken( RecordInputStream& rStrm )
1479 sal_uInt16 nFlags, nTableId, nCol1, nCol2;
1480 rStrm.skip( 3 );
1481 rStrm >> nFlags >> nTableId;
1482 rStrm.skip( 2 );
1483 rStrm >> nCol1 >> nCol2;
1484 TableRef xTable = getTables().getTable( nTableId );
1485 sal_Int32 nTokenIndex = xTable.get() ? xTable->getTokenIndex() : -1;
1486 if( nTokenIndex >= 0 )
1488 sal_Int32 nWidth = xTable->getWidth();
1489 sal_Int32 nHeight = xTable->getHeight();
1490 sal_Int32 nStartCol = 0;
1491 sal_Int32 nEndCol = nWidth - 1;
1492 sal_Int32 nStartRow = 0;
1493 sal_Int32 nEndRow = nHeight - 1;
1494 bool bFixedStartRow = true;
1495 bool bFixedHeight = false;
1497 bool bSingleCol = getFlag( nFlags, OOBIN_TOK_TABLE_COLUMN );
1498 bool bColRange = getFlag( nFlags, OOBIN_TOK_TABLE_COLRANGE );
1499 bool bValidRef = !bSingleCol || !bColRange;
1500 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - illegal combination of single column and column range" );
1501 if( bValidRef )
1503 if( bSingleCol )
1504 nStartCol = nEndCol = nCol1;
1505 else if( bColRange )
1506 { nStartCol = nCol1; nEndCol = nCol2; }
1507 bValidRef = (nStartCol <= nEndCol) && (nEndCol < nWidth);
1508 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid column range" );
1511 if( bValidRef )
1513 bool bAllRows = getFlag( nFlags, OOBIN_TOK_TABLE_ALL );
1514 bool bHeaderRows = getFlag( nFlags, OOBIN_TOK_TABLE_HEADERS );
1515 bool bDataRows = getFlag( nFlags, OOBIN_TOK_TABLE_DATA );
1516 bool bTotalsRows = getFlag( nFlags, OOBIN_TOK_TABLE_TOTALS );
1517 bool bThisRow = getFlag( nFlags, OOBIN_TOK_TABLE_THISROW );
1519 sal_Int32 nStartDataRow = xTable->getHeaderRows();
1520 sal_Int32 nEndDataRow = nEndRow - xTable->getTotalsRows();
1521 bValidRef = (nStartRow <= nStartDataRow) && (nStartDataRow <= nEndDataRow) && (nEndDataRow <= nEndRow);
1522 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid data row range" );
1523 if( bValidRef )
1525 if( bAllRows )
1527 bValidRef = !bHeaderRows && !bDataRows && !bTotalsRows && !bThisRow;
1528 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#All] table token" );
1530 else if( bHeaderRows )
1532 bValidRef = !bTotalsRows && !bThisRow;
1533 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Headers] table token" );
1534 nEndRow = bDataRows ? nEndDataRow : (nStartDataRow - 1);
1535 bFixedHeight = !bDataRows;
1537 else if( bDataRows )
1539 bValidRef = !bThisRow;
1540 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Data] table token" );
1541 nStartRow = nStartDataRow;
1542 if( !bTotalsRows ) nEndRow = nEndDataRow;
1544 else if( bTotalsRows )
1546 bValidRef = !bThisRow;
1547 OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Totals] table token" );
1548 nStartRow = nEndDataRow + 1;
1549 bFixedStartRow = false;
1550 bFixedHeight = !bDataRows;
1552 else if( bThisRow )
1554 nStartRow = nEndRow = getFormulaContext().getBaseAddress().Row - xTable->getRange().StartRow;
1555 bFixedHeight = true;
1557 else
1559 // nothing is the same as [#Data]
1560 nStartRow = nStartDataRow;
1561 nEndRow = nEndDataRow;
1564 if( bValidRef )
1565 bValidRef = (0 <= nStartRow) && (nStartRow <= nEndRow) && (nEndRow < nHeight);
1567 if( bValidRef )
1569 // push single database area token, if table token refers to entire table
1570 if( (nStartCol == 0) && (nEndCol + 1 == nWidth) && (nStartRow == 0) && (nEndRow + 1 == nHeight) )
1571 return pushValueOperand( nTokenIndex, OPCODE_DBAREA );
1572 // create an OFFSET function call to refer to a subrange of the table
1573 const FunctionInfo* pRowsInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_ROWS );
1574 const FunctionInfo* pColumnsInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_COLUMNS );
1575 return
1576 pRowsInfo && pColumnsInfo &&
1577 pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1578 (bFixedStartRow ?
1579 pushValueOperandToken< double >( nStartRow ) :
1580 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1581 pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1582 pushValueOperandToken< double >( nHeight - nStartRow ) &&
1583 pushBinaryOperatorToken( OPCODE_SUB ))) &&
1584 pushValueOperandToken< double >( nStartCol ) &&
1585 (bFixedHeight ?
1586 pushValueOperandToken< double >( nEndRow - nStartRow + 1 ) :
1587 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1588 pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1589 (((nStartRow == 0) && (nEndRow + 1 == nHeight)) ||
1590 (pushValueOperandToken< double >( nHeight - (nEndRow - nStartRow + 1) ) &&
1591 pushBinaryOperatorToken( OPCODE_SUB ))))) &&
1592 (((nStartCol == 0) && (nEndCol + 1 == nWidth)) ?
1593 (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1594 pushFunctionOperatorToken( *pColumnsInfo, 1 )) :
1595 pushValueOperandToken< double >( nEndCol - nStartCol + 1 )) &&
1596 pushOobFunction( OOBIN_FUNC_OFFSET, 5 );
1599 return pushBiffErrorOperand( BIFF_ERR_REF );
1602 bool OoxFormulaParserImpl::importArrayToken( RecordInputStream& rStrm )
1604 rStrm.skip( 14 );
1606 // start token array with opening brace and leading spaces
1607 pushOperand( OPCODE_ARRAY_OPEN );
1608 size_t nOpSize = popOperandSize();
1609 size_t nOldArraySize = getFormulaSize();
1611 // read array size
1612 swapStreamPosition( rStrm );
1613 sal_Int32 nRows = rStrm.readInt32();
1614 sal_Int32 nCols = rStrm.readInt32();
1615 OSL_ENSURE( (nCols > 0) && (nRows > 0), "OoxFormulaParserImpl::importArrayToken - empty array" );
1617 // read array values and build token array
1618 for( sal_Int32 nRow = 0; !rStrm.isEof() && (nRow < nRows); ++nRow )
1620 if( nRow > 0 )
1621 appendRawToken( OPCODE_ARRAY_ROWSEP );
1622 for( sal_Int32 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
1624 if( nCol > 0 )
1625 appendRawToken( OPCODE_ARRAY_COLSEP );
1626 switch( rStrm.readuInt8() )
1628 case OOBIN_TOK_ARRAY_DOUBLE:
1629 appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
1630 break;
1631 case OOBIN_TOK_ARRAY_STRING:
1632 appendRawToken( OPCODE_PUSH ) <<= rStrm.readString( false );
1633 break;
1634 case OOBIN_TOK_ARRAY_BOOL:
1635 appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
1636 break;
1637 case OOBIN_TOK_ARRAY_ERROR:
1638 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
1639 rStrm.skip( 3 );
1640 break;
1641 default:
1642 OSL_ENSURE( false, "OoxFormulaParserImpl::importArrayToken - unknown data type" );
1643 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
1647 swapStreamPosition( rStrm );
1649 // close token array and set resulting operand size
1650 appendRawToken( OPCODE_ARRAY_CLOSE );
1651 pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
1652 return true;
1655 bool OoxFormulaParserImpl::importRefToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1657 BinSingleRef2d aRef;
1658 aRef.readOobData( rStrm, bRelativeAsOffset );
1659 return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1662 bool OoxFormulaParserImpl::importAreaToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1664 BinComplexRef2d aRef;
1665 aRef.readOobData( rStrm, bRelativeAsOffset );
1666 return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1669 bool OoxFormulaParserImpl::importRef3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1671 LinkSheetRange aSheetRange = readSheetRange( rStrm );
1672 BinSingleRef2d aRef;
1673 aRef.readOobData( rStrm, bRelativeAsOffset );
1674 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1677 bool OoxFormulaParserImpl::importArea3dToken( RecordInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1679 LinkSheetRange aSheetRange = readSheetRange( rStrm );
1680 BinComplexRef2d aRef;
1681 aRef.readOobData( rStrm, bRelativeAsOffset );
1682 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1685 bool OoxFormulaParserImpl::importMemAreaToken( RecordInputStream& rStrm, bool bAddData )
1687 rStrm.skip( 6 );
1688 if( bAddData )
1689 skipMemAreaAddData( rStrm );
1690 return true;
1693 bool OoxFormulaParserImpl::importMemFuncToken( RecordInputStream& rStrm )
1695 rStrm.skip( 2 );
1696 return true;
1699 bool OoxFormulaParserImpl::importNameToken( RecordInputStream& rStrm )
1701 return pushOobName( rStrm.readInt32() );
1704 bool OoxFormulaParserImpl::importNameXToken( RecordInputStream& rStrm )
1706 sal_Int32 nRefId = rStrm.readInt16();
1707 sal_Int32 nNameId = rStrm.readInt32();
1708 return pushOobExtName( nRefId, nNameId );
1711 bool OoxFormulaParserImpl::importFuncToken( RecordInputStream& rStrm )
1713 sal_uInt16 nFuncId;
1714 rStrm >> nFuncId;
1715 return pushOobFunction( nFuncId );
1718 bool OoxFormulaParserImpl::importFuncVarToken( RecordInputStream& rStrm )
1720 sal_uInt8 nParamCount;
1721 sal_uInt16 nFuncId;
1722 rStrm >> nParamCount >> nFuncId;
1723 return pushOobFunction( nFuncId, nParamCount );
1726 bool OoxFormulaParserImpl::importExpToken( RecordInputStream& rStrm )
1728 BinAddress aBaseAddr;
1729 rStrm >> aBaseAddr.mnRow;
1730 swapStreamPosition( rStrm );
1731 rStrm >> aBaseAddr.mnCol;
1732 swapStreamPosition( rStrm );
1733 setSharedFormula( aBaseAddr );
1734 // formula has been set, exit parser by returning false
1735 return false;
1738 LinkSheetRange OoxFormulaParserImpl::readSheetRange( RecordInputStream& rStrm )
1740 return getExternalLinks().getSheetRange( rStrm.readInt16() );
1743 void OoxFormulaParserImpl::swapStreamPosition( RecordInputStream& rStrm )
1745 sal_Int64 nRecPos = rStrm.tell();
1746 rStrm.seek( mnAddDataPos );
1747 mnAddDataPos = nRecPos;
1750 void OoxFormulaParserImpl::skipMemAreaAddData( RecordInputStream& rStrm )
1752 swapStreamPosition( rStrm );
1753 rStrm.skip( 16 * rStrm.readInt32() );
1754 swapStreamPosition( rStrm );
1757 // convert BIN token and push API operand or operator -------------------------
1759 bool OoxFormulaParserImpl::pushOobName( sal_Int32 nNameId )
1761 // one-based in OOBIN formulas
1762 return pushDefinedNameOperand( getDefinedNames().getByIndex( nNameId - 1 ) );
1765 bool OoxFormulaParserImpl::pushOobExtName( sal_Int32 nRefId, sal_Int32 nNameId )
1767 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
1769 if( pExtLink->getLinkType() == LINKTYPE_SELF )
1770 return pushOobName( nNameId );
1771 // external name indexes are one-based in OOBIN
1772 ExternalNameRef xExtName = pExtLink->getNameByIndex( nNameId - 1 );
1773 return pushExternalNameOperand( xExtName, *pExtLink );
1775 return pushBiffErrorOperand( BIFF_ERR_NAME );
1778 bool OoxFormulaParserImpl::pushOobFunction( sal_uInt16 nFuncId )
1780 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( nFuncId ) )
1781 if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
1782 return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
1783 return pushFunctionOperator( OPCODE_NONAME, 0 );
1786 bool OoxFormulaParserImpl::pushOobFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
1788 if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
1789 nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
1790 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( nFuncId ) )
1791 return pushFunctionOperator( *pFuncInfo, nParamCount );
1792 return pushFunctionOperator( OPCODE_NONAME, nParamCount );
1795 // BIFF parser implementation =================================================
1797 namespace {
1799 /** A natural language reference struct with relative flag. */
1800 struct BiffNlr
1802 sal_Int32 mnCol; /// Column index.
1803 sal_Int32 mnRow; /// Row index.
1804 bool mbRel; /// True = relative column/row reference.
1806 explicit BiffNlr();
1808 void readBiff8Data( BiffInputStream& rStrm );
1811 BiffNlr::BiffNlr() :
1812 mnCol( 0 ),
1813 mnRow( 0 ),
1814 mbRel( false )
1818 void BiffNlr::readBiff8Data( BiffInputStream& rStrm )
1820 sal_uInt16 nRow, nCol;
1821 rStrm >> nRow >> nCol;
1822 mnCol = nCol & BIFF_TOK_NLR_MASK;
1823 mnRow = nRow;
1824 mbRel = getFlag( nCol, BIFF_TOK_NLR_REL );
1827 bool lclIsValidNlrStack( const BinAddress& rAddr1, const BinAddress& rAddr2, bool bRow )
1829 return bRow ?
1830 ((rAddr1.mnRow == rAddr2.mnRow) && (rAddr1.mnCol + 1 == rAddr2.mnCol)) :
1831 ((rAddr1.mnCol == rAddr2.mnCol) && (rAddr1.mnRow + 1 == rAddr2.mnRow));
1834 bool lclIsValidNlrRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
1836 return bRow ?
1837 ((rNlr.mnRow == rRange.maFirst.mnRow) && (rNlr.mnCol + 1 == rRange.maFirst.mnCol) && (rRange.maFirst.mnRow == rRange.maLast.mnRow)) :
1838 ((rNlr.mnCol == rRange.maFirst.mnCol) && (rNlr.mnRow + 1 == rRange.maFirst.mnRow) && (rRange.maFirst.mnCol == rRange.maLast.mnCol));
1841 } // namespace
1843 // ----------------------------------------------------------------------------
1845 class BiffFormulaParserImpl : public FormulaParserImpl
1847 public:
1848 explicit BiffFormulaParserImpl( const FormulaParser& rParent );
1850 virtual void importBiffFormula(
1851 FormulaContext& rContext,
1852 BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
1854 private:
1855 // import token contents and create API formula token ---------------------
1857 bool importTokenNotAvailable( BiffInputStream& rStrm );
1858 bool importRefTokenNotAvailable( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1859 bool importStrToken2( BiffInputStream& rStrm );
1860 bool importStrToken8( BiffInputStream& rStrm );
1861 bool importAttrToken( BiffInputStream& rStrm );
1862 bool importSpaceToken3( BiffInputStream& rStrm );
1863 bool importSpaceToken4( BiffInputStream& rStrm );
1864 bool importSheetToken2( BiffInputStream& rStrm );
1865 bool importSheetToken3( BiffInputStream& rStrm );
1866 bool importEndSheetToken2( BiffInputStream& rStrm );
1867 bool importEndSheetToken3( BiffInputStream& rStrm );
1868 bool importNlrToken( BiffInputStream& rStrm );
1869 bool importArrayToken( BiffInputStream& rStrm );
1870 bool importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1871 bool importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1872 bool importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1873 bool importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1874 bool importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1875 bool importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1876 bool importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1877 bool importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1878 bool importMemAreaToken( BiffInputStream& rStrm, bool bAddData );
1879 bool importMemFuncToken( BiffInputStream& rStrm );
1880 bool importNameToken( BiffInputStream& rStrm );
1881 bool importNameXToken( BiffInputStream& rStrm );
1882 bool importFuncToken2( BiffInputStream& rStrm );
1883 bool importFuncToken4( BiffInputStream& rStrm );
1884 bool importFuncVarToken2( BiffInputStream& rStrm );
1885 bool importFuncVarToken4( BiffInputStream& rStrm );
1886 bool importFuncCEToken( BiffInputStream& rStrm );
1887 bool importExpToken5( BiffInputStream& rStrm );
1889 bool importNlrAddrToken( BiffInputStream& rStrm, bool bRow );
1890 bool importNlrRangeToken( BiffInputStream& rStrm );
1891 bool importNlrSAddrToken( BiffInputStream& rStrm, bool bRow );
1892 bool importNlrSRangeToken( BiffInputStream& rStrm );
1893 bool importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nSkip );
1895 sal_Int32 readRefId( BiffInputStream& rStrm );
1896 sal_uInt16 readNameId( BiffInputStream& rStrm );
1897 LinkSheetRange readSheetRange5( BiffInputStream& rStrm );
1898 LinkSheetRange readSheetRange8( BiffInputStream& rStrm );
1900 void swapStreamPosition( BiffInputStream& rStrm );
1901 void skipMemAreaAddData( BiffInputStream& rStrm );
1902 bool readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow );
1903 bool readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm );
1905 // convert BIFF token and push API operand or operator --------------------
1907 bool pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
1908 bool pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
1909 bool pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow );
1910 bool pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange );
1911 bool pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow );
1912 bool pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow );
1913 bool pushBiffName( sal_uInt16 nNameId );
1914 bool pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId );
1915 bool pushBiffFunction( sal_uInt16 nFuncId );
1916 bool pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
1918 // ------------------------------------------------------------------------
1919 private:
1920 typedef bool (BiffFormulaParserImpl::*ImportTokenFunc)( BiffInputStream& );
1921 typedef bool (BiffFormulaParserImpl::*ImportRefTokenFunc)( BiffInputStream&, bool, bool );
1923 ImportTokenFunc mpImportStrToken; /// Pointer to tStr import function (string constant).
1924 ImportTokenFunc mpImportSpaceToken; /// Pointer to tAttrSpace import function (spaces/line breaks).
1925 ImportTokenFunc mpImportSheetToken; /// Pointer to tSheet import function (external reference).
1926 ImportTokenFunc mpImportEndSheetToken; /// Pointer to tEndSheet import function (end of external reference).
1927 ImportTokenFunc mpImportNlrToken; /// Pointer to tNlr import function (natural language reference).
1928 ImportRefTokenFunc mpImportRefToken; /// Pointer to tRef import function (2d cell reference).
1929 ImportRefTokenFunc mpImportAreaToken; /// Pointer to tArea import function (2d area reference).
1930 ImportRefTokenFunc mpImportRef3dToken; /// Pointer to tRef3d import function (3d cell reference).
1931 ImportRefTokenFunc mpImportArea3dToken; /// Pointer to tArea3d import function (3d area reference).
1932 ImportTokenFunc mpImportNameXToken; /// Pointer to tNameX import function (external name).
1933 ImportTokenFunc mpImportFuncToken; /// Pointer to tFunc import function (function with fixed parameter count).
1934 ImportTokenFunc mpImportFuncVarToken; /// Pointer to tFuncVar import function (function with variable parameter count).
1935 ImportTokenFunc mpImportFuncCEToken; /// Pointer to tFuncCE import function (command macro call).
1936 ImportTokenFunc mpImportExpToken; /// Pointer to tExp import function (array/shared formula).
1937 sal_Int64 mnAddDataPos; /// Current stream position for additional data (tArray, tMemArea, tNlr).
1938 sal_Int32 mnCurrRefId; /// Current ref-id from tSheet token (BIFF2-BIFF4 only).
1939 sal_uInt16 mnAttrDataSize; /// Size of one tAttr data element.
1940 sal_uInt16 mnArraySize; /// Size of tArray data.
1941 sal_uInt16 mnNameSize; /// Size of tName data.
1942 sal_uInt16 mnMemAreaSize; /// Size of tMemArea data.
1943 sal_uInt16 mnMemFuncSize; /// Size of tMemFunc data.
1944 sal_uInt16 mnRefIdSize; /// Size of unused data following a reference identifier.
1947 // ----------------------------------------------------------------------------
1949 BiffFormulaParserImpl::BiffFormulaParserImpl( const FormulaParser& rParent ) :
1950 FormulaParserImpl( rParent ),
1951 mnAddDataPos( 0 ),
1952 mnCurrRefId( 0 )
1954 switch( getBiff() )
1956 case BIFF2:
1957 mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
1958 mpImportSpaceToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1959 mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken2;
1960 mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken2;
1961 mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1962 mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
1963 mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
1964 mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1965 mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1966 mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1967 mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
1968 mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
1969 mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
1970 mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1971 mnAttrDataSize = 1;
1972 mnArraySize = 6;
1973 mnNameSize = 5;
1974 mnMemAreaSize = 4;
1975 mnMemFuncSize = 1;
1976 mnRefIdSize = 1;
1977 break;
1978 case BIFF3:
1979 mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
1980 mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken3;
1981 mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
1982 mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
1983 mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1984 mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
1985 mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
1986 mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1987 mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1988 mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1989 mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
1990 mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
1991 mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
1992 mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1993 mnAttrDataSize = 2;
1994 mnArraySize = 7;
1995 mnNameSize = 8;
1996 mnMemAreaSize = 6;
1997 mnMemFuncSize = 2;
1998 mnRefIdSize = 2;
1999 break;
2000 case BIFF4:
2001 mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
2002 mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2003 mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
2004 mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
2005 mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2006 mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
2007 mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
2008 mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2009 mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2010 mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2011 mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2012 mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2013 mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2014 mpImportExpToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2015 mnAttrDataSize = 2;
2016 mnArraySize = 7;
2017 mnNameSize = 8;
2018 mnMemAreaSize = 6;
2019 mnMemFuncSize = 2;
2020 mnRefIdSize = 2;
2021 break;
2022 case BIFF5:
2023 mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
2024 mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2025 mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2026 mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2027 mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2028 mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
2029 mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
2030 mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken5;
2031 mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken5;
2032 mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
2033 mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2034 mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2035 mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2036 mpImportExpToken = &BiffFormulaParserImpl::importExpToken5;
2037 mnAttrDataSize = 2;
2038 mnArraySize = 7;
2039 mnNameSize = 12;
2040 mnMemAreaSize = 6;
2041 mnMemFuncSize = 2;
2042 mnRefIdSize = 8;
2043 break;
2044 case BIFF8:
2045 mpImportStrToken = &BiffFormulaParserImpl::importStrToken8;
2046 mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2047 mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2048 mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2049 mpImportNlrToken = &BiffFormulaParserImpl::importNlrToken;
2050 mpImportRefToken = &BiffFormulaParserImpl::importRefToken8;
2051 mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken8;
2052 mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken8;
2053 mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken8;
2054 mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
2055 mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2056 mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2057 mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2058 mpImportExpToken = &BiffFormulaParserImpl::importExpToken5;
2059 mnAttrDataSize = 2;
2060 mnArraySize = 7;
2061 mnNameSize = 2;
2062 mnMemAreaSize = 6;
2063 mnMemFuncSize = 2;
2064 mnRefIdSize = 0;
2065 break;
2066 case BIFF_UNKNOWN: break;
2070 void BiffFormulaParserImpl::importBiffFormula( FormulaContext& rContext,
2071 BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
2073 initializeImport( rContext );
2074 mnCurrRefId = 0;
2076 sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
2077 sal_Int64 nEndPos = mnAddDataPos = rStrm.tell() + nFmlaSize;
2078 bool bRelativeAsOffset = getFormulaContext().isRelativeAsOffset();
2080 bool bOk = true;
2081 while( bOk && !rStrm.isEof() && (rStrm.tell() < nEndPos) )
2083 sal_uInt8 nTokenId;
2084 rStrm >> nTokenId;
2085 sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
2086 sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
2088 bOk = !getFlag( nTokenId, BIFF_TOKFLAG_INVALID );
2089 if( bOk )
2091 if( nTokenClass == BIFF_TOKCLASS_NONE )
2093 // base tokens
2094 switch( nBaseId )
2096 case BIFF_TOKID_EXP: bOk = (this->*mpImportExpToken)( rStrm ); break;
2097 case BIFF_TOKID_TBL: bOk = false; /* multiple op. will be set externally */ break;
2098 case BIFF_TOKID_ADD: bOk = pushBinaryOperator( OPCODE_ADD ); break;
2099 case BIFF_TOKID_SUB: bOk = pushBinaryOperator( OPCODE_SUB ); break;
2100 case BIFF_TOKID_MUL: bOk = pushBinaryOperator( OPCODE_MULT ); break;
2101 case BIFF_TOKID_DIV: bOk = pushBinaryOperator( OPCODE_DIV ); break;
2102 case BIFF_TOKID_POWER: bOk = pushBinaryOperator( OPCODE_POWER ); break;
2103 case BIFF_TOKID_CONCAT: bOk = pushBinaryOperator( OPCODE_CONCAT ); break;
2104 case BIFF_TOKID_LT: bOk = pushBinaryOperator( OPCODE_LESS ); break;
2105 case BIFF_TOKID_LE: bOk = pushBinaryOperator( OPCODE_LESS_EQUAL ); break;
2106 case BIFF_TOKID_EQ: bOk = pushBinaryOperator( OPCODE_EQUAL ); break;
2107 case BIFF_TOKID_GE: bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL ); break;
2108 case BIFF_TOKID_GT: bOk = pushBinaryOperator( OPCODE_GREATER ); break;
2109 case BIFF_TOKID_NE: bOk = pushBinaryOperator( OPCODE_NOT_EQUAL ); break;
2110 case BIFF_TOKID_ISECT: bOk = pushBinaryOperator( OPCODE_INTERSECT ); break;
2111 case BIFF_TOKID_LIST: bOk = pushBinaryOperator( OPCODE_LIST ); break;
2112 case BIFF_TOKID_RANGE: bOk = pushBinaryOperator( OPCODE_RANGE ); break;
2113 case BIFF_TOKID_UPLUS: bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN ); break;
2114 case BIFF_TOKID_UMINUS: bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN ); break;
2115 case BIFF_TOKID_PERCENT: bOk = pushUnaryPostOperator( OPCODE_PERCENT ); break;
2116 case BIFF_TOKID_PAREN: bOk = pushParenthesesOperator(); break;
2117 case BIFF_TOKID_MISSARG: bOk = pushOperand( OPCODE_MISSING ); break;
2118 case BIFF_TOKID_STR: bOk = (this->*mpImportStrToken)( rStrm ); break;
2119 case BIFF_TOKID_NLR: bOk = (this->*mpImportNlrToken)( rStrm ); break;
2120 case BIFF_TOKID_ATTR: bOk = importAttrToken( rStrm ); break;
2121 case BIFF_TOKID_SHEET: bOk = (this->*mpImportSheetToken)( rStrm ); break;
2122 case BIFF_TOKID_ENDSHEET: bOk = (this->*mpImportEndSheetToken)( rStrm ); break;
2123 case BIFF_TOKID_ERR: bOk = pushBiffErrorOperand( rStrm.readuInt8() ); break;
2124 case BIFF_TOKID_BOOL: bOk = pushBiffBoolOperand( rStrm.readuInt8() ); break;
2125 case BIFF_TOKID_INT: bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
2126 case BIFF_TOKID_NUM: bOk = pushValueOperand( rStrm.readDouble() ); break;
2127 default: bOk = false;
2130 else
2132 // classified tokens
2133 switch( nBaseId )
2135 case BIFF_TOKID_ARRAY: bOk = importArrayToken( rStrm ); break;
2136 case BIFF_TOKID_FUNC: bOk = (this->*mpImportFuncToken)( rStrm ); break;
2137 case BIFF_TOKID_FUNCVAR: bOk = (this->*mpImportFuncVarToken)( rStrm ); break;
2138 case BIFF_TOKID_NAME: bOk = importNameToken( rStrm ); break;
2139 case BIFF_TOKID_REF: bOk = (this->*mpImportRefToken)( rStrm, false, false ); break;
2140 case BIFF_TOKID_AREA: bOk = (this->*mpImportAreaToken)( rStrm, false, false ); break;
2141 case BIFF_TOKID_MEMAREA: bOk = importMemAreaToken( rStrm, true ); break;
2142 case BIFF_TOKID_MEMERR: bOk = importMemAreaToken( rStrm, false ); break;
2143 case BIFF_TOKID_MEMNOMEM: bOk = importMemAreaToken( rStrm, false ); break;
2144 case BIFF_TOKID_MEMFUNC: bOk = importMemFuncToken( rStrm ); break;
2145 case BIFF_TOKID_REFERR: bOk = (this->*mpImportRefToken)( rStrm, true, false ); break;
2146 case BIFF_TOKID_AREAERR: bOk = (this->*mpImportAreaToken)( rStrm, true, false ); break;
2147 case BIFF_TOKID_REFN: bOk = (this->*mpImportRefToken)( rStrm, false, true ); break;
2148 case BIFF_TOKID_AREAN: bOk = (this->*mpImportAreaToken)( rStrm, false, true ); break;
2149 case BIFF_TOKID_MEMAREAN: bOk = importMemFuncToken( rStrm ); break;
2150 case BIFF_TOKID_MEMNOMEMN: bOk = importMemFuncToken( rStrm ); break;
2151 case BIFF_TOKID_FUNCCE: bOk = (this->*mpImportFuncCEToken)( rStrm ); break;
2152 case BIFF_TOKID_NAMEX: bOk = (this->*mpImportNameXToken)( rStrm ); break;
2153 case BIFF_TOKID_REF3D: bOk = (this->*mpImportRef3dToken)( rStrm, false, bRelativeAsOffset ); break;
2154 case BIFF_TOKID_AREA3D: bOk = (this->*mpImportArea3dToken)( rStrm, false, bRelativeAsOffset ); break;
2155 case BIFF_TOKID_REFERR3D: bOk = (this->*mpImportRef3dToken)( rStrm, true, bRelativeAsOffset ); break;
2156 case BIFF_TOKID_AREAERR3D: bOk = (this->*mpImportArea3dToken)( rStrm, true, bRelativeAsOffset ); break;
2157 default: bOk = false;
2163 // build and finalize the token sequence
2164 if( bOk && (rStrm.tell() == nEndPos) )
2165 finalizeImport();
2167 // seek behind additional token data of tArray, tMemArea, tNlr tokens
2168 rStrm.seek( mnAddDataPos );
2171 // import token contents and create API formula token -------------------------
2173 bool BiffFormulaParserImpl::importTokenNotAvailable( BiffInputStream& )
2175 // dummy function for pointer-to-member-function
2176 return false;
2179 bool BiffFormulaParserImpl::importRefTokenNotAvailable( BiffInputStream&, bool, bool )
2181 // dummy function for pointer-to-member-function
2182 return false;
2185 bool BiffFormulaParserImpl::importStrToken2( BiffInputStream& rStrm )
2187 return pushValueOperand( rStrm.readByteStringUC( false, getTextEncoding(), getFormulaContext().isNulCharsAllowed() ) );
2190 bool BiffFormulaParserImpl::importStrToken8( BiffInputStream& rStrm )
2192 // read flags field for empty strings also
2193 return pushValueOperand( rStrm.readUniStringBody( rStrm.readuInt8(), getFormulaContext().isNulCharsAllowed() ) );
2196 bool BiffFormulaParserImpl::importAttrToken( BiffInputStream& rStrm )
2198 bool bOk = true;
2199 sal_uInt8 nType;
2200 rStrm >> nType;
2201 switch( nType )
2203 case 0: // sometimes, tAttrSkip tokens miss the type flag
2204 case BIFF_TOK_ATTR_VOLATILE:
2205 case BIFF_TOK_ATTR_IF:
2206 case BIFF_TOK_ATTR_SKIP:
2207 case BIFF_TOK_ATTR_ASSIGN:
2208 rStrm.skip( mnAttrDataSize );
2209 break;
2210 case BIFF_TOK_ATTR_CHOOSE:
2211 rStrm.skip( mnAttrDataSize * (1 + ((getBiff() == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16())) );
2212 break;
2213 case BIFF_TOK_ATTR_SUM:
2214 rStrm.skip( mnAttrDataSize );
2215 bOk = pushBiffFunction( BIFF_FUNC_SUM, 1 );
2216 break;
2217 case BIFF_TOK_ATTR_SPACE:
2218 case BIFF_TOK_ATTR_SPACE_VOLATILE:
2219 bOk = (this->*mpImportSpaceToken)( rStrm );
2220 break;
2221 default:
2222 bOk = false;
2224 return bOk;
2227 bool BiffFormulaParserImpl::importSpaceToken3( BiffInputStream& rStrm )
2229 rStrm.skip( 2 );
2230 return true;
2233 bool BiffFormulaParserImpl::importSpaceToken4( BiffInputStream& rStrm )
2235 sal_uInt8 nType, nCount;
2236 rStrm >> nType >> nCount;
2237 switch( nType )
2239 case BIFF_TOK_ATTR_SPACE_SP:
2240 appendLeadingSpaces( nCount, false );
2241 break;
2242 case BIFF_TOK_ATTR_SPACE_BR:
2243 appendLeadingSpaces( nCount, true );
2244 break;
2245 case BIFF_TOK_ATTR_SPACE_SP_OPEN:
2246 appendOpeningSpaces( nCount, false );
2247 break;
2248 case BIFF_TOK_ATTR_SPACE_BR_OPEN:
2249 appendOpeningSpaces( nCount, true );
2250 break;
2251 case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
2252 appendClosingSpaces( nCount, false );
2253 break;
2254 case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
2255 appendClosingSpaces( nCount, true );
2256 break;
2258 return true;
2261 bool BiffFormulaParserImpl::importSheetToken2( BiffInputStream& rStrm )
2263 rStrm.skip( 4 );
2264 mnCurrRefId = readRefId( rStrm );
2265 return true;
2268 bool BiffFormulaParserImpl::importSheetToken3( BiffInputStream& rStrm )
2270 rStrm.skip( 6 );
2271 mnCurrRefId = readRefId( rStrm );
2272 return true;
2275 bool BiffFormulaParserImpl::importEndSheetToken2( BiffInputStream& rStrm )
2277 rStrm.skip( 3 );
2278 mnCurrRefId = 0;
2279 return true;
2282 bool BiffFormulaParserImpl::importEndSheetToken3( BiffInputStream& rStrm )
2284 rStrm.skip( 4 );
2285 mnCurrRefId = 0;
2286 return true;
2289 bool BiffFormulaParserImpl::importNlrToken( BiffInputStream& rStrm )
2291 bool bOk = true;
2292 sal_uInt8 nNlrType;
2293 rStrm >> nNlrType;
2294 switch( nNlrType )
2296 case BIFF_TOK_NLR_ERR: bOk = importNlrErrToken( rStrm, 4 ); break;
2297 case BIFF_TOK_NLR_ROWR: bOk = importNlrAddrToken( rStrm, true ); break;
2298 case BIFF_TOK_NLR_COLR: bOk = importNlrAddrToken( rStrm, false ); break;
2299 case BIFF_TOK_NLR_ROWV: bOk = importNlrAddrToken( rStrm, true ); break;
2300 case BIFF_TOK_NLR_COLV: bOk = importNlrAddrToken( rStrm, false ); break;
2301 case BIFF_TOK_NLR_RANGE: bOk = importNlrRangeToken( rStrm ); break;
2302 case BIFF_TOK_NLR_SRANGE: bOk = importNlrSRangeToken( rStrm ); break;
2303 case BIFF_TOK_NLR_SROWR: bOk = importNlrSAddrToken( rStrm, true ); break;
2304 case BIFF_TOK_NLR_SCOLR: bOk = importNlrSAddrToken( rStrm, false ); break;
2305 case BIFF_TOK_NLR_SROWV: bOk = importNlrSAddrToken( rStrm, true ); break;
2306 case BIFF_TOK_NLR_SCOLV: bOk = importNlrSAddrToken( rStrm, false ); break;
2307 case BIFF_TOK_NLR_RANGEERR: bOk = importNlrErrToken( rStrm, 13 ); break;
2308 case BIFF_TOK_NLR_SXNAME: bOk = importNlrErrToken( rStrm, 4 ); break;
2309 default: bOk = false;
2311 return bOk;
2314 bool BiffFormulaParserImpl::importArrayToken( BiffInputStream& rStrm )
2316 rStrm.skip( mnArraySize );
2318 // start token array with opening brace and leading spaces
2319 pushOperand( OPCODE_ARRAY_OPEN );
2320 size_t nOpSize = popOperandSize();
2321 size_t nOldArraySize = getFormulaSize();
2322 bool bBiff8 = getBiff() == BIFF8;
2323 bool bNulChars = getFormulaContext().isNulCharsAllowed();
2325 // read array size
2326 swapStreamPosition( rStrm );
2327 sal_uInt16 nCols = rStrm.readuInt8();
2328 sal_uInt16 nRows = rStrm.readuInt16();
2329 if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
2330 OSL_ENSURE( (nCols > 0) && (nRows > 0), "BiffFormulaParserImpl::importArrayToken - empty array" );
2332 // read array values and build token array
2333 for( sal_uInt16 nRow = 0; !rStrm.isEof() && (nRow < nRows); ++nRow )
2335 if( nRow > 0 )
2336 appendRawToken( OPCODE_ARRAY_ROWSEP );
2337 for( sal_uInt16 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
2339 if( nCol > 0 )
2340 appendRawToken( OPCODE_ARRAY_COLSEP );
2341 switch( rStrm.readuInt8() )
2343 case BIFF_DATATYPE_EMPTY:
2344 appendRawToken( OPCODE_PUSH ) <<= OUString();
2345 rStrm.skip( 8 );
2346 break;
2347 case BIFF_DATATYPE_DOUBLE:
2348 appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
2349 break;
2350 case BIFF_DATATYPE_STRING:
2351 appendRawToken( OPCODE_PUSH ) <<= bBiff8 ?
2352 rStrm.readUniString( bNulChars ) :
2353 rStrm.readByteStringUC( false, getTextEncoding(), bNulChars );
2354 break;
2355 case BIFF_DATATYPE_BOOL:
2356 appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
2357 rStrm.skip( 7 );
2358 break;
2359 case BIFF_DATATYPE_ERROR:
2360 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
2361 rStrm.skip( 7 );
2362 break;
2363 default:
2364 OSL_ENSURE( false, "BiffFormulaParserImpl::importArrayToken - unknown data type" );
2365 appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
2369 swapStreamPosition( rStrm );
2371 // close token array and set resulting operand size
2372 appendRawToken( OPCODE_ARRAY_CLOSE );
2373 pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
2374 return true;
2377 bool BiffFormulaParserImpl::importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2379 BinSingleRef2d aRef;
2380 aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2381 return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2384 bool BiffFormulaParserImpl::importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2386 BinSingleRef2d aRef;
2387 aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2388 return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2391 bool BiffFormulaParserImpl::importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2393 BinComplexRef2d aRef;
2394 aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2395 return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2398 bool BiffFormulaParserImpl::importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2400 BinComplexRef2d aRef;
2401 aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2402 return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2405 bool BiffFormulaParserImpl::importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2407 LinkSheetRange aSheetRange = readSheetRange5( rStrm );
2408 BinSingleRef2d aRef;
2409 aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2410 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2413 bool BiffFormulaParserImpl::importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2415 LinkSheetRange aSheetRange = readSheetRange8( rStrm );
2416 BinSingleRef2d aRef;
2417 aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2418 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2421 bool BiffFormulaParserImpl::importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2423 LinkSheetRange aSheetRange = readSheetRange5( rStrm );
2424 BinComplexRef2d aRef;
2425 aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2426 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2429 bool BiffFormulaParserImpl::importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2431 LinkSheetRange aSheetRange = readSheetRange8( rStrm );
2432 BinComplexRef2d aRef;
2433 aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2434 return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2437 bool BiffFormulaParserImpl::importMemAreaToken( BiffInputStream& rStrm, bool bAddData )
2439 rStrm.skip( mnMemAreaSize );
2440 if( bAddData )
2441 skipMemAreaAddData( rStrm );
2442 return true;
2445 bool BiffFormulaParserImpl::importMemFuncToken( BiffInputStream& rStrm )
2447 rStrm.skip( mnMemFuncSize );
2448 return true;
2451 bool BiffFormulaParserImpl::importNameToken( BiffInputStream& rStrm )
2453 sal_uInt16 nNameId = readNameId( rStrm );
2454 return (mnCurrRefId > 0) ? pushBiffExtName( mnCurrRefId, nNameId ) : pushBiffName( nNameId );
2457 bool BiffFormulaParserImpl::importNameXToken( BiffInputStream& rStrm )
2459 sal_Int32 nRefId = readRefId( rStrm );
2460 sal_uInt16 nNameId = readNameId( rStrm );
2461 return pushBiffExtName( nRefId, nNameId );
2464 bool BiffFormulaParserImpl::importFuncToken2( BiffInputStream& rStrm )
2466 sal_uInt8 nFuncId;
2467 rStrm >> nFuncId;
2468 return pushBiffFunction( nFuncId );
2471 bool BiffFormulaParserImpl::importFuncToken4( BiffInputStream& rStrm )
2473 sal_uInt16 nFuncId;
2474 rStrm >> nFuncId;
2475 return pushBiffFunction( nFuncId );
2478 bool BiffFormulaParserImpl::importFuncVarToken2( BiffInputStream& rStrm )
2480 sal_uInt8 nParamCount, nFuncId;
2481 rStrm >> nParamCount >> nFuncId;
2482 return pushBiffFunction( nFuncId, nParamCount );
2485 bool BiffFormulaParserImpl::importFuncVarToken4( BiffInputStream& rStrm )
2487 sal_uInt8 nParamCount;
2488 sal_uInt16 nFuncId;
2489 rStrm >> nParamCount >> nFuncId;
2490 return pushBiffFunction( nFuncId, nParamCount & BIFF_TOK_FUNCVAR_COUNTMASK );
2493 bool BiffFormulaParserImpl::importFuncCEToken( BiffInputStream& rStrm )
2495 sal_uInt8 nParamCount, nFuncId;
2496 rStrm >> nParamCount >> nFuncId;
2497 sal_uInt16 nCmdId = nFuncId;
2498 setFlag( nCmdId, BIFF_TOK_FUNCVAR_CMD );
2499 return pushBiffFunction( nCmdId, nParamCount );
2502 bool BiffFormulaParserImpl::importExpToken5( BiffInputStream& rStrm )
2504 BinAddress aBaseAddr;
2505 aBaseAddr.read( rStrm );
2506 setSharedFormula( aBaseAddr );
2507 // formula has been set, exit parser by returning false
2508 return false;
2511 bool BiffFormulaParserImpl::importNlrAddrToken( BiffInputStream& rStrm, bool bRow )
2513 BiffNlr aNlr;
2514 aNlr.readBiff8Data( rStrm );
2515 return pushBiffNlrAddr( aNlr, bRow );
2518 bool BiffFormulaParserImpl::importNlrRangeToken( BiffInputStream& rStrm )
2520 BiffNlr aNlr;
2521 aNlr.readBiff8Data( rStrm );
2522 rStrm.skip( 1 );
2523 BinRange aRange;
2524 rStrm >> aRange;
2525 return pushBiffNlrRange( aNlr, aRange );
2528 bool BiffFormulaParserImpl::importNlrSAddrToken( BiffInputStream& rStrm, bool bRow )
2530 rStrm.skip( 4 );
2531 BiffNlr aNlr;
2532 return readNlrSAddrAddData( aNlr, rStrm, bRow ) ? pushBiffNlrSAddr( aNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2535 bool BiffFormulaParserImpl::importNlrSRangeToken( BiffInputStream& rStrm )
2537 rStrm.skip( 5 );
2538 BinRange aRange;
2539 rStrm >> aRange;
2540 BiffNlr aNlr;
2541 bool bRow;
2542 return readNlrSRangeAddData( aNlr, bRow, rStrm ) ? pushBiffNlrSRange( aNlr, aRange, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2545 bool BiffFormulaParserImpl::importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nIgnore )
2547 rStrm.skip( nIgnore );
2548 return pushBiffErrorOperand( BIFF_ERR_NAME );
2551 sal_Int32 BiffFormulaParserImpl::readRefId( BiffInputStream& rStrm )
2553 sal_Int16 nRefId;
2554 rStrm >> nRefId;
2555 rStrm.skip( mnRefIdSize );
2556 return nRefId;
2559 sal_uInt16 BiffFormulaParserImpl::readNameId( BiffInputStream& rStrm )
2561 sal_uInt16 nNameId;
2562 rStrm >> nNameId;
2563 rStrm.skip( mnNameSize );
2564 return nNameId;
2567 LinkSheetRange BiffFormulaParserImpl::readSheetRange5( BiffInputStream& rStrm )
2569 sal_Int32 nRefId = readRefId( rStrm );
2570 sal_Int16 nTab1, nTab2;
2571 rStrm >> nTab1 >> nTab2;
2572 return getExternalLinks().getSheetRange( nRefId, nTab1, nTab2 );
2575 LinkSheetRange BiffFormulaParserImpl::readSheetRange8( BiffInputStream& rStrm )
2577 return getExternalLinks().getSheetRange( readRefId( rStrm ) );
2580 void BiffFormulaParserImpl::swapStreamPosition( BiffInputStream& rStrm )
2582 sal_Int64 nRecPos = rStrm.tell();
2583 rStrm.seek( mnAddDataPos );
2584 mnAddDataPos = nRecPos;
2587 void BiffFormulaParserImpl::skipMemAreaAddData( BiffInputStream& rStrm )
2589 swapStreamPosition( rStrm );
2590 sal_Int32 nCount = rStrm.readuInt16();
2591 rStrm.skip( ((getBiff() == BIFF8) ? 8 : 6) * nCount );
2592 swapStreamPosition( rStrm );
2595 bool BiffFormulaParserImpl::readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow )
2597 bool bIsRow;
2598 return readNlrSRangeAddData( orNlr, bIsRow, rStrm ) && (bIsRow == bRow);
2601 bool BiffFormulaParserImpl::readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm )
2603 swapStreamPosition( rStrm );
2604 // read number of cell addresses and relative flag
2605 sal_uInt32 nCount;
2606 rStrm >> nCount;
2607 bool bRel = getFlag( nCount, BIFF_TOK_NLR_ADDREL );
2608 nCount &= BIFF_TOK_NLR_ADDMASK;
2609 sal_Int64 nEndPos = rStrm.tell() + 4 * nCount;
2610 // read list of cell addresses
2611 bool bValid = false;
2612 if( nCount >= 2 )
2614 // detect column/row orientation
2615 BinAddress aAddr1, aAddr2;
2616 rStrm >> aAddr1 >> aAddr2;
2617 orbIsRow = aAddr1.mnRow == aAddr2.mnRow;
2618 bValid = lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
2619 // read and verify additional cell positions
2620 for( sal_uInt32 nIndex = 2; bValid && (nIndex < nCount); ++nIndex )
2622 aAddr1 = aAddr2;
2623 rStrm >> aAddr2;
2624 bValid = !rStrm.isEof() && lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
2626 // check that last imported position (aAddr2) is not at the end of the sheet
2627 bValid = bValid && (orbIsRow ? (aAddr2.mnCol < mnMaxApiCol) : (aAddr2.mnRow < mnMaxApiRow));
2628 // fill the NLR struct with the last imported position
2629 if( bValid )
2631 orNlr.mnCol = aAddr2.mnCol;
2632 orNlr.mnRow = aAddr2.mnRow;
2633 orNlr.mbRel = bRel;
2636 // seek to end of additional data for this token
2637 rStrm.seek( nEndPos );
2638 swapStreamPosition( rStrm );
2640 return bValid;
2643 // convert BIFF token and push API operand or operator ------------------------
2645 bool BiffFormulaParserImpl::pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
2647 return (mnCurrRefId > 0) ?
2648 pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
2649 pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
2652 bool BiffFormulaParserImpl::pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
2654 return (mnCurrRefId > 0) ?
2655 pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
2656 pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
2659 bool BiffFormulaParserImpl::pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow )
2661 BinSingleRef2d aRef;
2662 aRef.mnCol = rNlr.mnCol;
2663 aRef.mnRow = rNlr.mnRow;
2664 aRef.mbColRel = !bRow;
2665 aRef.mbRowRel = bRow;
2666 return pushNlrOperand( aRef );
2669 bool BiffFormulaParserImpl::pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange )
2671 bool bRow = rNlr.mnRow == rRange.maFirst.mnRow;
2672 return lclIsValidNlrRange( rNlr, rRange, bRow ) ?
2673 pushBiffNlrAddr( rNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2676 bool BiffFormulaParserImpl::pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow )
2678 BinRange aRange;
2679 aRange.maFirst.mnCol = rNlr.mnCol + (bRow ? 1 : 0);
2680 aRange.maFirst.mnRow = rNlr.mnRow + (bRow ? 0 : 1);
2681 aRange.maLast.mnCol = bRow ? mnMaxApiCol : rNlr.mnCol;
2682 aRange.maLast.mnRow = bRow ? rNlr.mnRow : mnMaxApiRow;
2683 return pushBiffNlrSRange( rNlr, aRange, bRow );
2686 bool BiffFormulaParserImpl::pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
2688 if( lclIsValidNlrRange( rNlr, rRange, bRow ) )
2690 BinComplexRef2d aRef;
2691 aRef.maRef1.mnCol = rRange.maFirst.mnCol;
2692 aRef.maRef1.mnRow = rRange.maFirst.mnRow;
2693 aRef.maRef2.mnCol = rRange.maLast.mnCol;
2694 aRef.maRef2.mnRow = rRange.maLast.mnRow;
2695 aRef.maRef1.mbColRel = aRef.maRef2.mbColRel = !bRow && rNlr.mbRel;
2696 aRef.maRef1.mbRowRel = aRef.maRef2.mbRowRel = bRow && rNlr.mbRel;
2697 return pushReferenceOperand( aRef, false, false );
2699 return pushBiffErrorOperand( BIFF_ERR_REF );
2702 bool BiffFormulaParserImpl::pushBiffName( sal_uInt16 nNameId )
2704 // one-based in BIFF formulas
2705 return pushDefinedNameOperand( getDefinedNames().getByIndex( static_cast< sal_Int32 >( nNameId ) - 1 ) );
2708 bool BiffFormulaParserImpl::pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId )
2710 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
2712 if( pExtLink->getLinkType() == LINKTYPE_SELF )
2713 return pushBiffName( nNameId );
2714 // external name indexes are one-based in BIFF
2715 ExternalNameRef xExtName = pExtLink->getNameByIndex( static_cast< sal_Int32 >( nNameId ) - 1 );
2716 return pushExternalNameOperand( xExtName, *pExtLink );
2718 return pushBiffErrorOperand( BIFF_ERR_NAME );
2721 bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId )
2723 if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( nFuncId ) )
2724 if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
2725 return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
2726 return pushFunctionOperator( OPCODE_NONAME, 0 );
2729 bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
2731 if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
2732 nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
2733 if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( nFuncId ) )
2734 return pushFunctionOperator( *pFuncInfo, nParamCount );
2735 return pushFunctionOperator( OPCODE_NONAME, nParamCount );
2738 // ============================================================================
2740 FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
2741 FormulaProcessorBase( rHelper )
2743 switch( getFilterType() )
2745 case FILTER_OOX: mxImpl.reset( new OoxFormulaParserImpl( *this ) ); break;
2746 case FILTER_BIFF: mxImpl.reset( new BiffFormulaParserImpl( *this ) ); break;
2747 case FILTER_UNKNOWN: break;
2751 FormulaParser::~FormulaParser()
2755 void FormulaParser::importFormula( FormulaContext& rContext, const OUString& rFormulaString ) const
2757 OOX_LOADSAVE_TIMER( IMPORTFORMULA );
2758 mxImpl->importOoxFormula( rContext, rFormulaString );
2761 void FormulaParser::importFormula( FormulaContext& rContext, RecordInputStream& rStrm ) const
2763 OOX_LOADSAVE_TIMER( IMPORTFORMULA );
2764 mxImpl->importOobFormula( rContext, rStrm );
2767 void FormulaParser::importFormula( FormulaContext& rContext, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
2769 OOX_LOADSAVE_TIMER( IMPORTFORMULA );
2770 mxImpl->importBiffFormula( rContext, rStrm, pnFmlaSize );
2773 void FormulaParser::convertErrorToFormula( FormulaContext& rContext, sal_uInt8 nErrorCode ) const
2775 ApiTokenSequence aTokens( 3 );
2776 // HACK: enclose all error codes into an 1x1 matrix
2777 aTokens[ 0 ].OpCode = OPCODE_ARRAY_OPEN;
2778 aTokens[ 1 ].OpCode = OPCODE_PUSH;
2779 aTokens[ 1 ].Data <<= BiffHelper::calcDoubleFromError( nErrorCode );
2780 aTokens[ 2 ].OpCode = OPCODE_ARRAY_CLOSE;
2781 mxImpl->setFormula( rContext, aTokens );
2784 void FormulaParser::convertNameToFormula( FormulaContext& rContext, sal_Int32 nTokenIndex ) const
2786 if( nTokenIndex >= 0 )
2788 ApiTokenSequence aTokens( 1 );
2789 aTokens[ 0 ].OpCode = OPCODE_NAME;
2790 aTokens[ 0 ].Data <<= nTokenIndex;
2791 mxImpl->setFormula( rContext, aTokens );
2793 else
2794 convertErrorToFormula( rContext, BIFF_ERR_REF );
2797 void FormulaParser::convertNumberToHyperlink( FormulaContext& rContext, const OUString& rUrl, double fValue ) const
2799 OSL_ENSURE( rUrl.getLength() > 0, "FormulaParser::convertNumberToHyperlink - missing URL" );
2800 if( const FunctionInfo* pFuncInfo = getFuncInfoFromOobFuncId( OOBIN_FUNC_HYPERLINK ) )
2802 ApiTokenSequence aTokens( 6 );
2803 aTokens[ 0 ].OpCode = pFuncInfo->mnApiOpCode;
2804 aTokens[ 1 ].OpCode = OPCODE_OPEN;
2805 aTokens[ 2 ].OpCode = OPCODE_PUSH;
2806 aTokens[ 2 ].Data <<= rUrl;
2807 aTokens[ 3 ].OpCode = OPCODE_SEP;
2808 aTokens[ 4 ].OpCode = OPCODE_PUSH;
2809 aTokens[ 4 ].Data <<= fValue;
2810 aTokens[ 5 ].OpCode = OPCODE_CLOSE;
2811 mxImpl->setFormula( rContext, aTokens );
2815 OUString FormulaParser::importOleTargetLink( const OUString& rFormulaString )
2817 // obviously, this would overburden our formula parser, so we parse it manually
2818 OUString aTargetLink;
2819 sal_Int32 nFmlaLen = rFormulaString.getLength();
2820 if( (nFmlaLen >= 8) && (rFormulaString[ 0 ] == '[') )
2822 // passed string is trimmed already
2823 sal_Int32 nBracketClose = rFormulaString.indexOf( ']' );
2824 sal_Int32 nExclamation = rFormulaString.indexOf( '!' );
2825 if( (nBracketClose >= 2) &&
2826 (nBracketClose + 1 == nExclamation) &&
2827 (rFormulaString[ nExclamation + 1 ] == '\'') &&
2828 (rFormulaString[ nFmlaLen - 1 ] == '\'') )
2830 sal_Int32 nRefId = rFormulaString.copy( 1, nBracketClose - 1 ).toInt32();
2831 aTargetLink = mxImpl->resolveOleTarget( nRefId );
2834 return aTargetLink;
2837 OUString FormulaParser::importOleTargetLink( RecordInputStream& rStrm )
2839 OUString aTargetLink;
2840 sal_Int32 nFmlaSize = rStrm.readInt32();
2841 sal_Int64 nFmlaEndPos = rStrm.tell() + ::std::max< sal_Int32 >( nFmlaSize, 0 );
2842 if( (nFmlaSize == 7) && (rStrm.getRemaining() >= 7) )
2844 sal_uInt8 nToken;
2845 sal_Int16 nRefId;
2846 sal_Int32 nNameId;
2847 rStrm >> nToken >> nRefId >> nNameId;
2848 if( nToken == (BIFF_TOKCLASS_VAL|BIFF_TOKID_NAMEX) )
2849 aTargetLink = mxImpl->resolveOleTarget( nRefId );
2851 rStrm.seek( nFmlaEndPos );
2852 return aTargetLink;
2855 OUString FormulaParser::importOleTargetLink( BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
2857 OUString aTargetLink;
2858 sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
2859 rStrm.skip( nFmlaSize );
2860 return aTargetLink;
2863 // ============================================================================
2865 } // namespace xls
2866 } // namespace oox