xref: /trunk/main/oox/source/xls/formulaparser.cxx (revision ca5ec200)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "oox/xls/formulaparser.hxx"
25 
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/sheet/ComplexReference.hpp>
28 #include <com/sun/star/sheet/ExternalReference.hpp>
29 #include <com/sun/star/sheet/FormulaToken.hpp>
30 #include <com/sun/star/sheet/ReferenceFlags.hpp>
31 #include <com/sun/star/sheet/SingleReference.hpp>
32 #include "oox/core/filterbase.hxx"
33 #include "oox/xls/addressconverter.hxx"
34 #include "oox/xls/biffinputstream.hxx"
35 #include "oox/xls/defnamesbuffer.hxx"
36 #include "oox/xls/externallinkbuffer.hxx"
37 #include "oox/xls/tablebuffer.hxx"
38 #include "oox/xls/worksheethelper.hxx"
39 
40 namespace oox {
41 namespace xls {
42 
43 // ============================================================================
44 
45 using namespace ::com::sun::star::sheet;
46 using namespace ::com::sun::star::sheet::ReferenceFlags;
47 using namespace ::com::sun::star::table;
48 using namespace ::com::sun::star::uno;
49 
50 using ::rtl::OUString;
51 
52 // ============================================================================
53 
54 namespace {
55 
56 sal_uInt16 lclReadFmlaSize( BiffInputStream& rStrm, BiffType eBiff, const sal_uInt16* pnFmlaSize )
57 {
58     return pnFmlaSize ? *pnFmlaSize : ((eBiff == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16());
59 }
60 
61 } // namespace
62 
63 // formula finalizer ==========================================================
64 
65 FormulaFinalizer::FormulaFinalizer( const OpCodeProvider& rOpCodeProv ) :
66     OpCodeProvider( rOpCodeProv ),
67     ApiOpCodes( getOpCodes() )
68 {
69     maTokens.reserve( 0x2000 );
70 }
71 
72 ApiTokenSequence FormulaFinalizer::finalizeTokenArray( const ApiTokenSequence& rTokens )
73 {
74     maTokens.clear();
75     if( rTokens.hasElements() )
76     {
77         const ApiToken* pToken = rTokens.getConstArray();
78         processTokens( pToken, pToken + rTokens.getLength() );
79     }
80     return ContainerHelper::vectorToSequence( maTokens );
81 }
82 
83 const FunctionInfo* FormulaFinalizer::resolveBadFuncName( const OUString& ) const
84 {
85     return 0;
86 }
87 
88 OUString FormulaFinalizer::resolveDefinedName( sal_Int32 ) const
89 {
90     return OUString();
91 }
92 
93 const FunctionInfo* FormulaFinalizer::getFunctionInfo( ApiToken& orFuncToken )
94 {
95     // first, try to find a regular function info from token op-code
96     if( const FunctionInfo* pRegFuncInfo = getFuncInfoFromApiToken( orFuncToken ) )
97         return pRegFuncInfo;
98 
99     // try to recognize a function from an external library
100     if( (orFuncToken.OpCode == OPCODE_BAD) && orFuncToken.Data.has< OUString >() )
101     {
102         // virtual call to resolveBadFuncName()
103         if( const FunctionInfo* pLibFuncInfo = resolveBadFuncName( orFuncToken.Data.get< OUString >() ) )
104         {
105             // write function op-code to the OPCODE_BAD token
106             orFuncToken.OpCode = pLibFuncInfo->mnApiOpCode;
107             // if it is an external function, insert programmatic function name
108             if( (orFuncToken.OpCode == OPCODE_EXTERNAL) && (pLibFuncInfo->maExtProgName.getLength() > 0) )
109                 orFuncToken.Data <<= pLibFuncInfo->maExtProgName;
110             else
111                 orFuncToken.Data.clear();   // clear string from OPCODE_BAD
112             return pLibFuncInfo;
113         }
114     }
115 
116     // no success - return null
117     return 0;
118 }
119 
120 const FunctionInfo* FormulaFinalizer::getExternCallInfo( ApiToken& orFuncToken, const ApiToken& rECToken )
121 {
122     // try to resolve the passed token to a supported sheet function
123     if( const FunctionInfo* pFuncInfo = getFuncInfoFromApiToken( rECToken ) )
124     {
125         orFuncToken.OpCode = pFuncInfo->mnApiOpCode;
126         // programmatic add-in function name
127         if( (pFuncInfo->mnApiOpCode == OPCODE_EXTERNAL) && (pFuncInfo->maExtProgName.getLength() > 0) )
128             orFuncToken.Data <<= pFuncInfo->maExtProgName;
129         // name of unsupported function, convert to OPCODE_BAD to preserve the name
130         else if( (pFuncInfo->mnApiOpCode == OPCODE_BAD) && (pFuncInfo->maOoxFuncName.getLength() > 0) )
131             orFuncToken.Data <<= pFuncInfo->maOoxFuncName;
132         return pFuncInfo;
133     }
134 
135     // macro call or unknown function name, move data to function token
136     if( (rECToken.OpCode == OPCODE_MACRO) || (rECToken.OpCode == OPCODE_BAD) )
137         orFuncToken = rECToken;
138 
139     // defined name used as function call, convert to OPCODE_BAD to preserve the name
140     if( (rECToken.OpCode == OPCODE_NAME) && rECToken.Data.has< sal_Int32 >() )
141     {
142         OUString aDefName = resolveDefinedName( rECToken.Data.get< sal_Int32 >() );
143         if( aDefName.getLength() > 0 )
144         {
145             orFuncToken.OpCode = OPCODE_BAD;
146             orFuncToken.Data <<= aDefName;
147         }
148     }
149 
150     return 0;
151 }
152 
153 void FormulaFinalizer::processTokens( const ApiToken* pToken, const ApiToken* pTokenEnd )
154 {
155     while( pToken < pTokenEnd )
156     {
157         // push the current token into the vector
158         bool bValid = appendFinalToken( *pToken );
159         // try to process a function
160         if( const FunctionInfo* pFuncInfo = bValid ? getFunctionInfo( maTokens.back() ) : 0 )
161             pToken = processParameters( *pFuncInfo, pToken + 1, pTokenEnd );
162         // otherwise, go to next token
163         else
164             ++pToken;
165     }
166 }
167 
168 const ApiToken* FormulaFinalizer::processParameters(
169         const FunctionInfo& rFuncInfo, const ApiToken* pToken, const ApiToken* pTokenEnd )
170 {
171     // remember position of the token containing the function op-code
172     size_t nFuncNameIdx = maTokens.size() - 1;
173 
174     // process a function, if an OPCODE_OPEN token is following
175     OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::processParameters - OPCODE_OPEN expected" );
176     if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN) )
177     {
178         // append the OPCODE_OPEN token to the vector
179         maTokens.append( OPCODE_OPEN );
180 
181         // store positions of OPCODE_OPEN, parameter separators, and OPCODE_CLOSE
182         ParameterPosVector aParams;
183         pToken = findParameters( aParams, pToken, pTokenEnd );
184         OSL_ENSURE( aParams.size() >= 2, "FormulaFinalizer::processParameters - missing tokens" );
185         size_t nParamCount = aParams.size() - 1;
186 
187         if( (nParamCount == 1) && isEmptyParameter( aParams[ 0 ] + 1, aParams[ 1 ] ) )
188         {
189             /*  Empty pair of parentheses -> function call without parameters,
190                 process parameter, there might be spaces between parentheses. */
191             processTokens( aParams[ 0 ] + 1, aParams[ 1 ] );
192         }
193         else
194         {
195             const FunctionInfo* pRealFuncInfo = &rFuncInfo;
196             ParameterPosVector::const_iterator aPosIt = aParams.begin();
197 
198             /*  Preprocess EXTERN.CALL functions. The actual function name is
199                 contained as reference to a defined name in the first (hidden)
200                 parameter. */
201             if( rFuncInfo.mnBiffFuncId == BIFF_FUNC_EXTERNCALL )
202             {
203                 ApiToken& rFuncToken = maTokens[ nFuncNameIdx ];
204                 rFuncToken.OpCode = OPCODE_NONAME;
205 
206                 // try to initialize function token from first parameter
207                 if( const ApiToken* pECToken = getSingleToken( *aPosIt + 1, *(aPosIt + 1) ) )
208                     if( const FunctionInfo* pECFuncInfo = getExternCallInfo( rFuncToken, *pECToken ) )
209                         pRealFuncInfo = pECFuncInfo;
210 
211                 /*  On success (something has been inserted into rFuncToken),
212                     skip the first parameter. */
213                 if( rFuncToken.OpCode != OPCODE_NONAME )
214                 {
215                     --nParamCount;
216                     ++aPosIt;
217                 }
218             }
219 
220             // process all parameters
221             FunctionParamInfoIterator aParamInfoIt( *pRealFuncInfo );
222             size_t nLastValidSize = maTokens.size();
223             size_t nLastValidCount = 0;
224             for( size_t nParam = 0; nParam < nParamCount; ++nParam, ++aPosIt, ++aParamInfoIt )
225             {
226                 // add embedded Calc-only parameters
227                 if( aParamInfoIt.isCalcOnlyParam() )
228                 {
229                     appendCalcOnlyParameter( *pRealFuncInfo, nParam );
230                     while( aParamInfoIt.isCalcOnlyParam() ) ++aParamInfoIt;
231                 }
232 
233                 const ApiToken* pParamBegin = *aPosIt + 1;
234                 const ApiToken* pParamEnd = *(aPosIt + 1);
235                 bool bIsEmpty = isEmptyParameter( pParamBegin, pParamEnd );
236 
237                 if( !aParamInfoIt.isExcelOnlyParam() )
238                 {
239                     // handle empty parameters
240                     if( bIsEmpty )
241                     {
242                         // append leading space tokens from original token array
243                         while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
244                             maTokens.push_back( *pParamBegin++ );
245                         // add default values for some empty parameters, or the OPCODE_MISSING token
246                         appendEmptyParameter( *pRealFuncInfo, nParam );
247                         // reset bIsEmpty flag, if something has been appended in appendEmptyParameter()
248                         bIsEmpty = maTokens.back().OpCode == OPCODE_MISSING;
249                         // skip OPCODE_MISSING token in the original token array
250                         OSL_ENSURE( (pParamBegin == pParamEnd) || (pParamBegin->OpCode == OPCODE_MISSING), "FormulaFinalizer::processParameters - OPCODE_MISSING expected" );
251                         if( pParamBegin < pParamEnd ) ++pParamBegin;
252                         // append trailing space tokens from original token array
253                         while( (pParamBegin < pParamEnd) && (pParamBegin->OpCode == OPCODE_SPACES) )
254                             maTokens.push_back( *pParamBegin++ );
255                     }
256                     else
257                     {
258                         // if parameter is not empty, process all tokens of the parameter
259                         processTokens( pParamBegin, pParamEnd );
260                     }
261 
262                     // append parameter separator token
263                     maTokens.append( OPCODE_SEP );
264                 }
265 
266                 /*  #84453# Update size of new token sequence with valid parameters
267                     to be able to remove trailing optional empty parameters. */
268                 if( !bIsEmpty || (nParam < pRealFuncInfo->mnMinParamCount) )
269                 {
270                     nLastValidSize = maTokens.size();
271                     nLastValidCount = nParam + 1;
272                 }
273             }
274 
275             // #84453# remove trailing optional empty parameters
276             maTokens.resize( nLastValidSize );
277 
278             // add trailing Calc-only parameters
279             if( aParamInfoIt.isCalcOnlyParam() )
280                 appendCalcOnlyParameter( *pRealFuncInfo, nLastValidCount );
281 
282             // add optional parameters that are required in Calc
283             appendRequiredParameters( *pRealFuncInfo, nLastValidCount );
284 
285             // remove last parameter separator token
286             if( maTokens.back().OpCode == OPCODE_SEP )
287                 maTokens.pop_back();
288         }
289 
290         /*  Append the OPCODE_CLOSE token to the vector, but only if there is
291             no OPCODE_BAD token at the end, this token already contains the
292             trailing closing parentheses. */
293         if( (pTokenEnd - 1)->OpCode != OPCODE_BAD )
294             maTokens.append( OPCODE_CLOSE );
295     }
296 
297     /*  Replace OPCODE_EXTERNAL with OPCODE_NONAME to get #NAME! error in cell,
298         if no matching add-in function was found. */
299     ApiToken& rFuncNameToken = maTokens[ nFuncNameIdx ];
300     if( (rFuncNameToken.OpCode == OPCODE_EXTERNAL) && !rFuncNameToken.Data.hasValue() )
301         rFuncNameToken.OpCode = OPCODE_NONAME;
302 
303     return pToken;
304 }
305 
306 bool FormulaFinalizer::isEmptyParameter( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
307 {
308     while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
309     if( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_MISSING) ) ++pToken;
310     while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
311     return pToken == pTokenEnd;
312 }
313 
314 const ApiToken* FormulaFinalizer::getSingleToken( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
315 {
316     const ApiToken* pSingleToken = 0;
317     // skip leading whitespace tokens
318     while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
319     // remember first non-whitespace token
320     if( pToken < pTokenEnd ) pSingleToken = pToken++;
321     // skip trailing whitespace tokens
322     while( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_SPACES) ) ++pToken;
323     // return null, if other non-whitespace tokens follow
324     return (pToken == pTokenEnd) ? pSingleToken : 0;
325 }
326 
327 const ApiToken* FormulaFinalizer::skipParentheses( const ApiToken* pToken, const ApiToken* pTokenEnd ) const
328 {
329     // skip tokens between OPCODE_OPEN and OPCODE_CLOSE
330     OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "skipParentheses - OPCODE_OPEN expected" );
331     ++pToken;
332     while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
333     {
334         if( pToken->OpCode == OPCODE_OPEN )
335             pToken = skipParentheses( pToken, pTokenEnd );
336         else
337             ++pToken;
338     }
339     // skip the OPCODE_CLOSE token
340     OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "skipParentheses - OPCODE_CLOSE expected" );
341     return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
342 }
343 
344 const ApiToken* FormulaFinalizer::findParameters( ParameterPosVector& rParams,
345         const ApiToken* pToken, const ApiToken* pTokenEnd ) const
346 {
347     // push position of OPCODE_OPEN
348     OSL_ENSURE( (pToken < pTokenEnd) && (pToken->OpCode == OPCODE_OPEN), "FormulaFinalizer::findParameters - OPCODE_OPEN expected" );
349     rParams.push_back( pToken++ );
350 
351     // find positions of parameter separators
352     while( (pToken < pTokenEnd) && (pToken->OpCode != OPCODE_CLOSE) )
353     {
354         if( pToken->OpCode == OPCODE_OPEN )
355             pToken = skipParentheses( pToken, pTokenEnd );
356         else if( pToken->OpCode == OPCODE_SEP )
357             rParams.push_back( pToken++ );
358         else
359             ++pToken;
360     }
361 
362     // push position of OPCODE_CLOSE
363     OSL_ENSURE( ((pToken < pTokenEnd) && (pToken->OpCode == OPCODE_CLOSE)) || ((pTokenEnd - 1)->OpCode == OPCODE_BAD), "FormulaFinalizer::findParameters - OPCODE_CLOSE expected" );
364     rParams.push_back( pToken );
365     return (pToken < pTokenEnd) ? (pToken + 1) : pTokenEnd;
366 }
367 
368 void FormulaFinalizer::appendEmptyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
369 {
370     // remeber old size of the token array
371     size_t nTokenArraySize = maTokens.size();
372 
373     switch( rFuncInfo.mnBiff12FuncId )
374     {
375         case BIFF_FUNC_IF:
376             if( (nParam == 1) || (nParam == 2) )
377                 maTokens.append< double >( OPCODE_PUSH, 0.0 );
378         break;
379         default:;
380     }
381 
382     // if no token has been added, append a OPCODE_MISSING token
383     if( nTokenArraySize == maTokens.size() )
384         maTokens.append( OPCODE_MISSING );
385 }
386 
387 void FormulaFinalizer::appendCalcOnlyParameter( const FunctionInfo& rFuncInfo, size_t nParam )
388 {
389     (void)nParam;   // prevent 'unused' warning
390     switch( rFuncInfo.mnBiff12FuncId )
391     {
392         case BIFF_FUNC_FLOOR:
393         case BIFF_FUNC_CEILING:
394             OSL_ENSURE( nParam == 2, "FormulaFinalizer::appendCalcOnlyParameter - unexpected parameter index" );
395             maTokens.append< double >( OPCODE_PUSH, 1.0 );
396             maTokens.append( OPCODE_SEP );
397         break;
398     }
399 }
400 
401 void FormulaFinalizer::appendRequiredParameters( const FunctionInfo& rFuncInfo, size_t nParamCount )
402 {
403     switch( rFuncInfo.mnBiff12FuncId )
404     {
405         case BIFF_FUNC_WEEKNUM:
406             if( nParamCount == 1 )
407             {
408                 maTokens.append< double >( OPCODE_PUSH, 1.0 );
409                 maTokens.append( OPCODE_SEP );
410             }
411         break;
412     }
413 }
414 
415 bool FormulaFinalizer::appendFinalToken( const ApiToken& rToken )
416 {
417     // replace OPCODE_MACRO without macro name with #NAME? error code
418     bool bValid = (rToken.OpCode != OPCODE_MACRO) || rToken.Data.hasValue();
419     if( bValid )
420     {
421         maTokens.push_back( rToken );
422     }
423     else
424     {
425         maTokens.append( OPCODE_ARRAY_OPEN );
426         maTokens.append( OPCODE_PUSH, BiffHelper::calcDoubleFromError( BIFF_ERR_NAME ) );
427         maTokens.append( OPCODE_ARRAY_CLOSE );
428     }
429     return bValid;
430 }
431 
432 // parser implementation base =================================================
433 
434 class FormulaParserImpl : public FormulaFinalizer, public WorkbookHelper
435 {
436 public:
437     explicit            FormulaParserImpl( const FormulaParser& rParent );
438 
439     /** Converts an OOXML formula string. */
440     virtual ApiTokenSequence importOoxFormula(
441                             const CellAddress& rBaseAddress,
442                             const OUString& rFormulaString );
443 
444     /** Imports and converts a BIFF12 token array from the passed stream. */
445     virtual ApiTokenSequence importBiff12Formula(
446                             const CellAddress& rBaseAddress,
447                             FormulaType eType,
448                             SequenceInputStream& rStrm );
449 
450     /** Imports and converts a BIFF2-BIFF8 token array from the passed stream. */
451     virtual ApiTokenSequence importBiffFormula(
452                             const CellAddress& rBaseAddress,
453                             FormulaType eType,
454                             BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
455 
456     /** Tries to resolve the passed ref-id to an OLE target URL. */
457     OUString            resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const;
458 
459 protected:
460     typedef ::std::pair< sal_Int32, bool >  WhiteSpace;
461     typedef ::std::vector< WhiteSpace >     WhiteSpaceVec;
462 
463     /** Initializes the formula parser before importing a formula. */
464     void                initializeImport( const CellAddress& rBaseAddress, FormulaType eType );
465     /** Finalizes the internal token storage after import. */
466     ApiTokenSequence    finalizeImport();
467 
468     // token array ------------------------------------------------------------
469 
470     bool                resetSpaces();
471     static void         appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed );
472     void                appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed );
473     void                appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed );
474     void                appendClosingSpaces( sal_Int32 nCount, bool bLineFeed );
475 
476     size_t              getFormulaSize() const;
477     Any&                appendRawToken( sal_Int32 nOpCode );
478     Any&                insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd );
479     size_t              appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces );
480     size_t              insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd );
481 
482     size_t              getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const;
483     void                pushOperandSize( size_t nSize );
484     size_t              popOperandSize();
485 
486     ApiToken&           getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex );
487     void                removeOperand( size_t nOpCountFromEnd, size_t nOpIndex );
488     void                removeLastOperands( size_t nOpCountFromEnd );
489 
490     bool                pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
491     bool                pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
492     template< typename Type >
493     bool                pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
494     template< typename Type >
495     inline bool         pushValueOperandToken( const Type& rValue, const WhiteSpaceVec* pSpaces = 0 )
496                             { return pushValueOperandToken( rValue, OPCODE_PUSH, pSpaces ); }
497     bool                pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
498     bool                pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
499     bool                pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
500     bool                pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces = 0 );
501     bool                pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
502     bool                pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
503     bool                pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces = 0, const WhiteSpaceVec* pClosingSpaces = 0 );
504 
505     bool                pushOperand( sal_Int32 nOpCode );
506     bool                pushAnyOperand( const Any& rAny, sal_Int32 nOpCode );
507     template< typename Type >
508     bool                pushValueOperand( const Type& rValue, sal_Int32 nOpCode );
509     template< typename Type >
510     inline bool         pushValueOperand( const Type& rValue )
511                             { return pushValueOperand( rValue, OPCODE_PUSH ); }
512     bool                pushBoolOperand( bool bValue );
513     bool                pushErrorOperand( double fEncodedError );
514     bool                pushBiffBoolOperand( sal_uInt8 nValue );
515     bool                pushBiffErrorOperand( sal_uInt8 nErrorCode );
516     bool                pushParenthesesOperand();
517     bool                pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
518     bool                pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
519     template< typename Type >
520     bool                pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef );
521     bool                pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
522     bool                pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
523     bool                pushNlrOperand( const BinSingleRef2d& rRef );
524     bool                pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken );
525     bool                pushDefinedNameOperand( const DefinedNameRef& rxDefName );
526     bool                pushExternalFuncOperand( const FunctionInfo& rFuncInfo );
527     bool                pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem );
528     bool                pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink );
529     bool                pushSpecialTokenOperand( const BinAddress& rBaseAddr, bool bTable );
530 
531     bool                pushUnaryPreOperator( sal_Int32 nOpCode );
532     bool                pushUnaryPostOperator( sal_Int32 nOpCode );
533     bool                pushBinaryOperator( sal_Int32 nOpCode );
534     bool                pushParenthesesOperator();
535     bool                pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount );
536     bool                pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount );
537 
538 private:
539     // reference conversion ---------------------------------------------------
540 
541     void                initReference2d( SingleReference& orApiRef ) const;
542     void                initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet ) const;
543     void                convertColRow( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bRelativeAsOffset ) const;
544     void                convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
545     void                convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
546     void                convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
547     void                convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
548     void                convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const;
549     void                convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const;
550 
551 private:
552     // finalize token sequence ------------------------------------------------
553 
554     virtual const FunctionInfo* resolveBadFuncName( const OUString& rTokenData ) const;
555     virtual ::rtl::OUString resolveDefinedName( sal_Int32 nTokenIndex ) const;
556 
557 protected:
558     const sal_Int32     mnMaxApiCol;                /// Maximum column index in own document.
559     const sal_Int32     mnMaxApiRow;                /// Maximum row index in own document.
560     const sal_Int32     mnMaxXlsCol;                /// Maximum column index in imported document.
561     const sal_Int32     mnMaxXlsRow;                /// Maximum row index in imported document.
562 
563     CellAddress         maBaseAddr;                 /// Base address for relative references.
564     bool                mbRelativeAsOffset;         /// True = relative row/column index is (signed) offset, false = explicit index.
565     bool                mb2dRefsAs3dRefs;           /// True = convert all 2D references to 3D references in sheet specified by base address.
566     bool                mbSpecialTokens;            /// True = special handling for tExp and tTbl tokens, false = exit with error.
567     bool                mbAllowNulChars;            /// True = keep NUL characters in string tokens.
568 
569 private:
570     typedef ::std::vector< size_t > SizeTypeVector;
571 
572     ApiTokenVector      maTokenStorage;             /// Raw unordered token storage.
573     SizeTypeVector      maTokenIndexes;             /// Indexes into maTokenStorage.
574     SizeTypeVector      maOperandSizeStack;         /// Stack with token sizes per operand.
575     WhiteSpaceVec       maLeadingSpaces;            /// List of whitespaces before next token.
576     WhiteSpaceVec       maOpeningSpaces;            /// List of whitespaces before opening parenthesis.
577     WhiteSpaceVec       maClosingSpaces;            /// List of whitespaces before closing parenthesis.
578 };
579 
580 // ----------------------------------------------------------------------------
581 
582 FormulaParserImpl::FormulaParserImpl( const FormulaParser& rParent ) :
583     FormulaFinalizer( rParent ),
584     WorkbookHelper( rParent ),
585     mnMaxApiCol( rParent.getAddressConverter().getMaxApiAddress().Column ),
586     mnMaxApiRow( rParent.getAddressConverter().getMaxApiAddress().Row ),
587     mnMaxXlsCol( rParent.getAddressConverter().getMaxXlsAddress().Column ),
588     mnMaxXlsRow( rParent.getAddressConverter().getMaxXlsAddress().Row ),
589     mbRelativeAsOffset( false ),
590     mb2dRefsAs3dRefs( false ),
591     mbAllowNulChars( false )
592 {
593     // reserve enough space to make resize(), push_back() etc. cheap
594     maTokenStorage.reserve( 0x2000 );
595     maTokenIndexes.reserve( 0x2000 );
596     maOperandSizeStack.reserve( 256 );
597     maLeadingSpaces.reserve( 256 );
598     maOpeningSpaces.reserve( 256 );
599     maClosingSpaces.reserve( 256 );
600 }
601 
602 ApiTokenSequence FormulaParserImpl::importOoxFormula( const CellAddress&, const OUString& )
603 {
604     OSL_ENSURE( false, "FormulaParserImpl::importOoxFormula - not implemented" );
605     return ApiTokenSequence();
606 }
607 
608 ApiTokenSequence FormulaParserImpl::importBiff12Formula( const CellAddress&, FormulaType, SequenceInputStream& )
609 {
610     OSL_ENSURE( false, "FormulaParserImpl::importBiff12Formula - not implemented" );
611     return ApiTokenSequence();
612 }
613 
614 ApiTokenSequence FormulaParserImpl::importBiffFormula( const CellAddress&, FormulaType, BiffInputStream&, const sal_uInt16* )
615 {
616     OSL_ENSURE( false, "FormulaParserImpl::importBiffFormula - not implemented" );
617     return ApiTokenSequence();
618 }
619 
620 OUString FormulaParserImpl::resolveOleTarget( sal_Int32 nRefId, bool bUseRefSheets ) const
621 {
622     const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, bUseRefSheets ).get();
623     OSL_ENSURE( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE), "FormulaParserImpl::resolveOleTarget - missing or wrong link" );
624     if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_OLE) )
625          return getBaseFilter().getAbsoluteUrl( pExtLink->getTargetUrl() );
626     return OUString();
627 }
628 
629 void FormulaParserImpl::initializeImport( const CellAddress& rBaseAddr, FormulaType eType )
630 {
631     maBaseAddr = rBaseAddr;
632     mbRelativeAsOffset = mb2dRefsAs3dRefs = mbSpecialTokens = mbAllowNulChars = false;
633     switch( eType )
634     {
635         case FORMULATYPE_CELL:
636             mbSpecialTokens = true;
637         break;
638         case FORMULATYPE_ARRAY:
639         break;
640         case FORMULATYPE_SHAREDFORMULA:
641             mbRelativeAsOffset = true;
642         break;
643         case FORMULATYPE_CONDFORMAT:
644             mbRelativeAsOffset = true;
645         break;
646         case FORMULATYPE_VALIDATION:
647             mbRelativeAsOffset = true;
648             // enable NUL characters in BIFF import, string list is single tStr token with NUL separators
649             mbAllowNulChars = getFilterType() == FILTER_BIFF;
650         break;
651         case FORMULATYPE_DEFINEDNAME:
652             mbRelativeAsOffset = true;
653             // BIFF2-BIFF4: convert 2D referebces to absolute 3D references
654             mb2dRefsAs3dRefs = (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4);
655         break;
656     }
657 
658     maTokenStorage.clear();
659     maTokenIndexes.clear();
660     maOperandSizeStack.clear();
661 }
662 
663 ApiTokenSequence FormulaParserImpl::finalizeImport()
664 {
665     ApiTokenSequence aTokens( static_cast< sal_Int32 >( maTokenIndexes.size() ) );
666     if( aTokens.hasElements() )
667     {
668         ApiToken* pToken = aTokens.getArray();
669         for( SizeTypeVector::const_iterator aIt = maTokenIndexes.begin(), aEnd = maTokenIndexes.end(); aIt != aEnd; ++aIt, ++pToken )
670             *pToken = maTokenStorage[ *aIt ];
671     }
672     return finalizeTokenArray( aTokens );
673 }
674 
675 // token array ----------------------------------------------------------------
676 
677 bool FormulaParserImpl::resetSpaces()
678 {
679     maLeadingSpaces.clear();
680     maOpeningSpaces.clear();
681     maClosingSpaces.clear();
682     return true;
683 }
684 
685 void FormulaParserImpl::appendSpaces( WhiteSpaceVec& orSpaces, sal_Int32 nCount, bool bLineFeed )
686 {
687     OSL_ENSURE( nCount >= 0, "FormulaParserImpl::appendSpaces - negative count" );
688     if( nCount > 0 )
689         orSpaces.push_back( WhiteSpace( nCount, bLineFeed ) );
690 }
691 
692 void FormulaParserImpl::appendLeadingSpaces( sal_Int32 nCount, bool bLineFeed )
693 {
694     appendSpaces( maLeadingSpaces, nCount, bLineFeed );
695 }
696 
697 void FormulaParserImpl::appendOpeningSpaces( sal_Int32 nCount, bool bLineFeed )
698 {
699     appendSpaces( maOpeningSpaces, nCount, bLineFeed );
700 }
701 
702 void FormulaParserImpl::appendClosingSpaces( sal_Int32 nCount, bool bLineFeed )
703 {
704     appendSpaces( maClosingSpaces, nCount, bLineFeed );
705 }
706 
707 size_t FormulaParserImpl::getFormulaSize() const
708 {
709     return maTokenIndexes.size();
710 }
711 
712 Any& FormulaParserImpl::appendRawToken( sal_Int32 nOpCode )
713 {
714     maTokenIndexes.push_back( maTokenStorage.size() );
715     return maTokenStorage.append( nOpCode );
716 }
717 
718 Any& FormulaParserImpl::insertRawToken( sal_Int32 nOpCode, size_t nIndexFromEnd )
719 {
720     maTokenIndexes.insert( maTokenIndexes.end() - nIndexFromEnd, maTokenStorage.size() );
721     return maTokenStorage.append( nOpCode );
722 }
723 
724 size_t FormulaParserImpl::appendWhiteSpaceTokens( const WhiteSpaceVec* pSpaces )
725 {
726     if( pSpaces && !pSpaces->empty() )
727         for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
728             appendRawToken( OPCODE_SPACES ) <<= aIt->first;
729     return pSpaces ? pSpaces->size() : 0;
730 }
731 
732 size_t FormulaParserImpl::insertWhiteSpaceTokens( const WhiteSpaceVec* pSpaces, size_t nIndexFromEnd )
733 {
734     if( pSpaces && !pSpaces->empty() )
735         for( WhiteSpaceVec::const_iterator aIt = pSpaces->begin(), aEnd = pSpaces->end(); aIt != aEnd; ++aIt )
736             insertRawToken( OPCODE_SPACES, nIndexFromEnd ) <<= aIt->first;
737     return pSpaces ? pSpaces->size() : 0;
738 }
739 
740 size_t FormulaParserImpl::getOperandSize( size_t nOpCountFromEnd, size_t nOpIndex ) const
741 {
742     OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
743         "FormulaParserImpl::getOperandSize - invalid parameters" );
744     return maOperandSizeStack[ maOperandSizeStack.size() - nOpCountFromEnd + nOpIndex ];
745 }
746 
747 void FormulaParserImpl::pushOperandSize( size_t nSize )
748 {
749     maOperandSizeStack.push_back( nSize );
750 }
751 
752 size_t FormulaParserImpl::popOperandSize()
753 {
754     OSL_ENSURE( !maOperandSizeStack.empty(), "FormulaParserImpl::popOperandSize - invalid call" );
755     size_t nOpSize = maOperandSizeStack.back();
756     maOperandSizeStack.pop_back();
757     return nOpSize;
758 }
759 
760 ApiToken& FormulaParserImpl::getOperandToken( size_t nOpCountFromEnd, size_t nOpIndex, size_t nTokenIndex )
761 {
762     OSL_ENSURE( getOperandSize( nOpCountFromEnd, nOpIndex ) > nTokenIndex,
763         "FormulaParserImpl::getOperandToken - invalid parameters" );
764     SizeTypeVector::const_iterator aIndexIt = maTokenIndexes.end();
765     for( SizeTypeVector::const_iterator aEnd = maOperandSizeStack.end(), aIt = aEnd - nOpCountFromEnd + nOpIndex; aIt != aEnd; ++aIt )
766         aIndexIt -= *aIt;
767     return maTokenStorage[ *(aIndexIt + nTokenIndex) ];
768 }
769 
770 void FormulaParserImpl::removeOperand( size_t nOpCountFromEnd, size_t nOpIndex )
771 {
772     OSL_ENSURE( (nOpIndex < nOpCountFromEnd) && (nOpCountFromEnd <= maOperandSizeStack.size()),
773         "FormulaParserImpl::removeOperand - invalid parameters" );
774     // remove indexes into token storage, but do not touch storage itself
775     SizeTypeVector::iterator aSizeEnd = maOperandSizeStack.end();
776     SizeTypeVector::iterator aSizeIt = aSizeEnd - nOpCountFromEnd + nOpIndex;
777     size_t nRemainingSize = 0;
778     for( SizeTypeVector::iterator aIt = aSizeIt + 1; aIt != aSizeEnd; ++aIt )
779         nRemainingSize += *aIt;
780     maTokenIndexes.erase( maTokenIndexes.end() - nRemainingSize - *aSizeIt, maTokenIndexes.end() - nRemainingSize );
781     maOperandSizeStack.erase( aSizeIt );
782 }
783 
784 void FormulaParserImpl::removeLastOperands( size_t nOpCountFromEnd )
785 {
786     for( size_t nOpIndex = 0; nOpIndex < nOpCountFromEnd; ++nOpIndex )
787         removeOperand( 1, 0 );
788 }
789 
790 bool FormulaParserImpl::pushOperandToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
791 {
792     size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
793     appendRawToken( nOpCode );
794     pushOperandSize( nSpacesSize + 1 );
795     return true;
796 }
797 
798 bool FormulaParserImpl::pushAnyOperandToken( const Any& rAny, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
799 {
800     size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
801     appendRawToken( nOpCode ) = rAny;
802     pushOperandSize( nSpacesSize + 1 );
803     return true;
804 }
805 
806 template< typename Type >
807 bool FormulaParserImpl::pushValueOperandToken( const Type& rValue, sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
808 {
809     size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
810     appendRawToken( nOpCode ) <<= rValue;
811     pushOperandSize( nSpacesSize + 1 );
812     return true;
813 }
814 
815 bool FormulaParserImpl::pushParenthesesOperandToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
816 {
817     size_t nSpacesSize = appendWhiteSpaceTokens( pOpeningSpaces );
818     appendRawToken( OPCODE_OPEN );
819     nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
820     appendRawToken( OPCODE_CLOSE );
821     pushOperandSize( nSpacesSize + 2 );
822     return true;
823 }
824 
825 bool FormulaParserImpl::pushUnaryPreOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
826 {
827     bool bOk = maOperandSizeStack.size() >= 1;
828     if( bOk )
829     {
830         size_t nOpSize = popOperandSize();
831         size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOpSize );
832         insertRawToken( nOpCode, nOpSize );
833         pushOperandSize( nOpSize + nSpacesSize + 1 );
834     }
835     return bOk;
836 }
837 
838 bool FormulaParserImpl::pushUnaryPostOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
839 {
840     bool bOk = maOperandSizeStack.size() >= 1;
841     if( bOk )
842     {
843         size_t nOpSize = popOperandSize();
844         size_t nSpacesSize = appendWhiteSpaceTokens( pSpaces );
845         appendRawToken( nOpCode );
846         pushOperandSize( nOpSize + nSpacesSize + 1 );
847     }
848     return bOk;
849 }
850 
851 bool FormulaParserImpl::pushBinaryOperatorToken( sal_Int32 nOpCode, const WhiteSpaceVec* pSpaces )
852 {
853     bool bOk = maOperandSizeStack.size() >= 2;
854     if( bOk )
855     {
856         size_t nOp2Size = popOperandSize();
857         size_t nOp1Size = popOperandSize();
858         size_t nSpacesSize = insertWhiteSpaceTokens( pSpaces, nOp2Size );
859         insertRawToken( nOpCode, nOp2Size );
860         pushOperandSize( nOp1Size + nSpacesSize + 1 + nOp2Size );
861     }
862     return bOk;
863 }
864 
865 bool FormulaParserImpl::pushParenthesesOperatorToken( const WhiteSpaceVec* pOpeningSpaces, const WhiteSpaceVec* pClosingSpaces )
866 {
867     bool bOk = maOperandSizeStack.size() >= 1;
868     if( bOk )
869     {
870         size_t nOpSize = popOperandSize();
871         size_t nSpacesSize = insertWhiteSpaceTokens( pOpeningSpaces, nOpSize );
872         insertRawToken( OPCODE_OPEN, nOpSize );
873         nSpacesSize += appendWhiteSpaceTokens( pClosingSpaces );
874         appendRawToken( OPCODE_CLOSE );
875         pushOperandSize( nOpSize + nSpacesSize + 2 );
876     }
877     return bOk;
878 }
879 
880 bool FormulaParserImpl::pushFunctionOperatorToken( sal_Int32 nOpCode, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
881 {
882     /*  #i70925# if there are not enough tokens available on token stack, do
883         not exit with error, but reduce parameter count. */
884     nParamCount = ::std::min( maOperandSizeStack.size(), nParamCount );
885 
886     // convert all parameters on stack to a single operand separated with OPCODE_SEP
887     bool bOk = true;
888     for( size_t nParam = 1; bOk && (nParam < nParamCount); ++nParam )
889         bOk = pushBinaryOperatorToken( OPCODE_SEP );
890 
891     // add function parentheses and function name
892     return bOk &&
893         ((nParamCount > 0) ? pushParenthesesOperatorToken( 0, pClosingSpaces ) : pushParenthesesOperandToken( 0, pClosingSpaces )) &&
894         pushUnaryPreOperatorToken( nOpCode, pLeadingSpaces );
895 }
896 
897 bool FormulaParserImpl::pushFunctionOperatorToken( const FunctionInfo& rFuncInfo, size_t nParamCount, const WhiteSpaceVec* pLeadingSpaces, const WhiteSpaceVec* pClosingSpaces )
898 {
899     bool bOk = pushFunctionOperatorToken( rFuncInfo.mnApiOpCode, nParamCount, pLeadingSpaces, pClosingSpaces );
900     if( bOk )
901     {
902        // create an external add-in call for the passed built-in function
903         if( (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) && (rFuncInfo.maExtProgName.getLength() > 0) )
904             getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maExtProgName;
905         // create a bad token with unsupported function name
906         else if( (rFuncInfo.mnApiOpCode == OPCODE_BAD) && (rFuncInfo.maOoxFuncName.getLength() > 0) )
907             getOperandToken( 1, 0, 0 ).Data <<= rFuncInfo.maOoxFuncName;
908     }
909     return bOk;
910 }
911 
912 bool FormulaParserImpl::pushOperand( sal_Int32 nOpCode )
913 {
914     return pushOperandToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
915 }
916 
917 bool FormulaParserImpl::pushAnyOperand( const Any& rAny, sal_Int32 nOpCode )
918 {
919     return pushAnyOperandToken( rAny, nOpCode, &maLeadingSpaces ) && resetSpaces();
920 }
921 
922 template< typename Type >
923 bool FormulaParserImpl::pushValueOperand( const Type& rValue, sal_Int32 nOpCode )
924 {
925     return pushValueOperandToken( rValue, nOpCode, &maLeadingSpaces ) && resetSpaces();
926 }
927 
928 bool FormulaParserImpl::pushBoolOperand( bool bValue )
929 {
930     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( bValue ? BIFF_FUNC_TRUE : BIFF_FUNC_FALSE ) )
931         return pushFunctionOperator( pFuncInfo->mnApiOpCode, 0 );
932     return pushValueOperand< double >( bValue ? 1.0 : 0.0 );
933 }
934 
935 bool FormulaParserImpl::pushErrorOperand( double fEncodedError )
936 {
937     // HACK: enclose all error codes into an 1x1 matrix
938     // start token array with opening brace and leading spaces
939     pushOperand( OPCODE_ARRAY_OPEN );
940     size_t nOpSize = popOperandSize();
941     size_t nOldArraySize = maTokenIndexes.size();
942     // push a double containing the Calc error code
943     appendRawToken( OPCODE_PUSH ) <<= fEncodedError;
944     // close token array and set resulting operand size
945     appendRawToken( OPCODE_ARRAY_CLOSE );
946     pushOperandSize( nOpSize + maTokenIndexes.size() - nOldArraySize );
947     return true;
948 }
949 
950 bool FormulaParserImpl::pushBiffBoolOperand( sal_uInt8 nValue )
951 {
952     return pushBoolOperand( nValue != BIFF_TOK_BOOL_FALSE );
953 }
954 
955 bool FormulaParserImpl::pushBiffErrorOperand( sal_uInt8 nErrorCode )
956 {
957     return pushErrorOperand( BiffHelper::calcDoubleFromError( nErrorCode ) );
958 }
959 
960 bool FormulaParserImpl::pushParenthesesOperand()
961 {
962     return pushParenthesesOperandToken( &maOpeningSpaces, &maClosingSpaces ) && resetSpaces();
963 }
964 
965 bool FormulaParserImpl::pushReferenceOperand( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
966 {
967     SingleReference aApiRef;
968     convertReference2d( aApiRef, rRef, bDeleted, bRelativeAsOffset );
969     return pushValueOperand( aApiRef );
970 }
971 
972 bool FormulaParserImpl::pushReferenceOperand( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
973 {
974     ComplexReference aApiRef;
975     convertReference2d( aApiRef, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
976     return pushValueOperand( aApiRef );
977 }
978 
979 template< typename Type >
980 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const Type& rApiRef )
981 {
982     if( rSheetRange.isExternal() )
983     {
984         ExternalReference aApiExtRef;
985         aApiExtRef.Index = rSheetRange.getDocLinkIndex();
986         aApiExtRef.Reference <<= rApiRef;
987         return pushValueOperand( aApiExtRef );
988     }
989     return pushValueOperand( rApiRef );
990 }
991 
992 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
993 {
994     if( rSheetRange.is3dRange() )
995     {
996         // single-cell-range over several sheets, needs to create a ComplexReference
997         ComplexReference aApiRef;
998         convertReference3d( aApiRef, rSheetRange, rRef, rRef, bDeleted, bRelativeAsOffset );
999         return pushReferenceOperand( rSheetRange, aApiRef );
1000     }
1001     SingleReference aApiRef;
1002     convertReference3d( aApiRef, rSheetRange.getFirstSheet(), rSheetRange.isSameSheet(), rRef, bDeleted, bRelativeAsOffset );
1003     return pushReferenceOperand( rSheetRange, aApiRef );
1004 }
1005 
1006 bool FormulaParserImpl::pushReferenceOperand( const LinkSheetRange& rSheetRange, const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
1007 {
1008     ComplexReference aApiRef;
1009     convertReference3d( aApiRef, rSheetRange, rRef.maRef1, rRef.maRef2, bDeleted, bRelativeAsOffset );
1010     return pushReferenceOperand( rSheetRange, aApiRef );
1011 }
1012 
1013 bool FormulaParserImpl::pushNlrOperand( const BinSingleRef2d& rRef )
1014 {
1015     SingleReference aApiRef;
1016     convertReference2d( aApiRef, rRef, false, false );
1017     return pushValueOperand( aApiRef, OPCODE_NLR );
1018 }
1019 
1020 bool FormulaParserImpl::pushEmbeddedRefOperand( const DefinedNameBase& rName, bool bPushBadToken )
1021 {
1022     Any aRefAny = rName.getReference( maBaseAddr );
1023     if( aRefAny.hasValue() )
1024         return pushAnyOperand( aRefAny, OPCODE_PUSH );
1025     if( bPushBadToken && (rName.getModelName().getLength() > 0) && (rName.getModelName()[ 0 ] >= ' ') )
1026         return pushValueOperand( rName.getModelName(), OPCODE_BAD );
1027     return pushBiffErrorOperand( BIFF_ERR_NAME );
1028 }
1029 
1030 bool FormulaParserImpl::pushDefinedNameOperand( const DefinedNameRef& rxDefName )
1031 {
1032     if( !rxDefName || (rxDefName->getModelName().getLength() == 0) )
1033         return pushBiffErrorOperand( BIFF_ERR_NAME );
1034     if( rxDefName->isMacroFunction() )
1035         return pushValueOperand( rxDefName->getModelName(), OPCODE_MACRO );
1036     if( rxDefName->getTokenIndex() >= 0 )
1037         return pushValueOperand( rxDefName->getTokenIndex(), OPCODE_NAME );
1038     return pushEmbeddedRefOperand( *rxDefName, true );
1039 }
1040 
1041 bool FormulaParserImpl::pushExternalFuncOperand( const FunctionInfo& rFuncInfo )
1042 {
1043     return (rFuncInfo.mnApiOpCode == OPCODE_EXTERNAL) ?
1044         pushValueOperand( rFuncInfo.maExtProgName, OPCODE_EXTERNAL ) :
1045         pushOperand( rFuncInfo.mnApiOpCode );
1046 }
1047 
1048 bool FormulaParserImpl::pushDdeLinkOperand( const OUString& rDdeServer, const OUString& rDdeTopic, const OUString& rDdeItem )
1049 {
1050     // create the function call DDE("server";"topic";"item")
1051     return
1052         pushValueOperandToken( rDdeServer ) &&
1053         pushValueOperandToken( rDdeTopic ) &&
1054         pushValueOperandToken( rDdeItem ) &&
1055         pushFunctionOperator( OPCODE_DDE, 3 );
1056 }
1057 
1058 bool FormulaParserImpl::pushExternalNameOperand( const ExternalNameRef& rxExtName, const ExternalLink& rExtLink )
1059 {
1060     if( rxExtName.get() ) switch( rExtLink.getLinkType() )
1061     {
1062         case LINKTYPE_INTERNAL:
1063         case LINKTYPE_EXTERNAL:
1064             return pushEmbeddedRefOperand( *rxExtName, false );
1065 
1066         case LINKTYPE_ANALYSIS:
1067             // TODO: need support for localized addin function names
1068             if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
1069                 return pushExternalFuncOperand( *pFuncInfo );
1070         break;
1071 
1072         case LINKTYPE_LIBRARY:
1073             if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( rxExtName->getUpcaseModelName() ) )
1074                 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == rExtLink.getFuncLibraryType()) )
1075                     return pushExternalFuncOperand( *pFuncInfo );
1076         break;
1077 
1078         case LINKTYPE_DDE:
1079         {
1080             OUString aDdeServer, aDdeTopic, aDdeItem;
1081             if( rxExtName->getDdeLinkData( aDdeServer, aDdeTopic, aDdeItem ) )
1082                 return pushDdeLinkOperand( aDdeServer, aDdeTopic, aDdeItem );
1083         }
1084         break;
1085 
1086         default:
1087             OSL_ENSURE( rExtLink.getLinkType() != LINKTYPE_SELF, "FormulaParserImpl::pushExternalNameOperand - invalid call" );
1088     }
1089     return pushBiffErrorOperand( BIFF_ERR_NAME );
1090 }
1091 
1092 bool FormulaParserImpl::pushSpecialTokenOperand( const BinAddress& rBaseAddr, bool bTable )
1093 {
1094     CellAddress aBaseAddr( maBaseAddr.Sheet, rBaseAddr.mnCol, rBaseAddr.mnRow );
1095     ApiSpecialTokenInfo aTokenInfo( aBaseAddr, bTable );
1096     return mbSpecialTokens && (getFormulaSize() == 0) && pushValueOperand( aTokenInfo, OPCODE_BAD );
1097 }
1098 
1099 bool FormulaParserImpl::pushUnaryPreOperator( sal_Int32 nOpCode )
1100 {
1101     return pushUnaryPreOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1102 }
1103 
1104 bool FormulaParserImpl::pushUnaryPostOperator( sal_Int32 nOpCode )
1105 {
1106     return pushUnaryPostOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1107 }
1108 
1109 bool FormulaParserImpl::pushBinaryOperator( sal_Int32 nOpCode )
1110 {
1111     return pushBinaryOperatorToken( nOpCode, &maLeadingSpaces ) && resetSpaces();
1112 }
1113 
1114 bool FormulaParserImpl::pushParenthesesOperator()
1115 {
1116     return pushParenthesesOperatorToken( &maOpeningSpaces, &maClosingSpaces ) && resetSpaces();
1117 }
1118 
1119 bool FormulaParserImpl::pushFunctionOperator( sal_Int32 nOpCode, size_t nParamCount )
1120 {
1121     return pushFunctionOperatorToken( nOpCode, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1122 }
1123 
1124 bool FormulaParserImpl::pushFunctionOperator( const FunctionInfo& rFuncInfo, size_t nParamCount )
1125 {
1126     return pushFunctionOperatorToken( rFuncInfo, nParamCount, &maLeadingSpaces, &maClosingSpaces ) && resetSpaces();
1127 }
1128 
1129 // reference conversion -------------------------------------------------------
1130 
1131 void FormulaParserImpl::initReference2d( SingleReference& orApiRef ) const
1132 {
1133     if( mb2dRefsAs3dRefs )
1134     {
1135         initReference3d( orApiRef, maBaseAddr.Sheet, false );
1136     }
1137     else
1138     {
1139         orApiRef.Flags = SHEET_RELATIVE;
1140         // #i10184# absolute sheet index needed for relative references in shared formulas
1141         orApiRef.Sheet = maBaseAddr.Sheet;
1142         orApiRef.RelativeSheet = 0;
1143     }
1144 }
1145 
1146 void FormulaParserImpl::initReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet ) const
1147 {
1148     orApiRef.Flags = SHEET_3D;
1149     if( nSheet < 0 )
1150     {
1151         orApiRef.Sheet = 0;
1152         orApiRef.Flags |= SHEET_DELETED;
1153     }
1154     else if( bSameSheet )
1155     {
1156         OSL_ENSURE( nSheet == 0, "FormulaParserImpl::initReference3d - invalid sheet index" );
1157         orApiRef.Flags |= SHEET_RELATIVE;
1158         orApiRef.RelativeSheet = 0;
1159     }
1160     else
1161     {
1162         orApiRef.Sheet = nSheet;
1163     }
1164 }
1165 
1166 void FormulaParserImpl::convertReference( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1167 {
1168     if( bDeleted )
1169     {
1170         orApiRef.Column = 0;
1171         orApiRef.Row = 0;
1172         // no explicit information about whether row or column is deleted
1173         orApiRef.Flags |= COLUMN_DELETED | ROW_DELETED;
1174     }
1175     else
1176     {
1177         // column/row indexes and flags
1178         setFlag( orApiRef.Flags, COLUMN_RELATIVE, rRef.mbColRel );
1179         setFlag( orApiRef.Flags, ROW_RELATIVE, rRef.mbRowRel );
1180         (rRef.mbColRel ? orApiRef.RelativeColumn : orApiRef.Column) = rRef.mnCol;
1181         (rRef.mbRowRel ? orApiRef.RelativeRow : orApiRef.Row) = rRef.mnRow;
1182         // convert absolute indexes to relative offsets used in API
1183         if( !bRelativeAsOffset )
1184         {
1185             if( rRef.mbColRel )
1186                 orApiRef.RelativeColumn -= maBaseAddr.Column;
1187             if( rRef.mbRowRel )
1188                 orApiRef.RelativeRow -= maBaseAddr.Row;
1189         }
1190     }
1191 }
1192 
1193 void FormulaParserImpl::convertReference( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1194 {
1195     convertReference( orApiRef.Reference1, rRef1, bDeleted, bRelativeAsOffset );
1196     convertReference( orApiRef.Reference2, rRef2, bDeleted, bRelativeAsOffset );
1197     /*  Handle references to complete rows or columns (e.g. $1:$2 or C:D),
1198         need to expand or shrink to limits of own document. */
1199     if( !bDeleted && !rRef1.mbColRel && !rRef2.mbColRel && (orApiRef.Reference1.Column == 0) && (orApiRef.Reference2.Column == mnMaxXlsCol) )
1200         orApiRef.Reference2.Column = mnMaxApiCol;
1201     if( !bDeleted && !rRef1.mbRowRel && !rRef2.mbRowRel && (orApiRef.Reference1.Row == 0) && (orApiRef.Reference2.Row == mnMaxXlsRow) )
1202         orApiRef.Reference2.Row = mnMaxApiRow;
1203 }
1204 
1205 void FormulaParserImpl::convertReference2d( SingleReference& orApiRef, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1206 {
1207     initReference2d( orApiRef );
1208     convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1209 }
1210 
1211 void FormulaParserImpl::convertReference2d( ComplexReference& orApiRef, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1212 {
1213     initReference2d( orApiRef.Reference1 );
1214     initReference2d( orApiRef.Reference2 );
1215     convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1216     // remove sheet name from second part of reference
1217     setFlag( orApiRef.Reference2.Flags, SHEET_3D, false );
1218 }
1219 
1220 void FormulaParserImpl::convertReference3d( SingleReference& orApiRef, sal_Int32 nSheet, bool bSameSheet, const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset ) const
1221 {
1222     initReference3d( orApiRef, nSheet, bSameSheet );
1223     convertReference( orApiRef, rRef, bDeleted, bRelativeAsOffset );
1224 }
1225 
1226 void FormulaParserImpl::convertReference3d( ComplexReference& orApiRef, const LinkSheetRange& rSheetRange, const BinSingleRef2d& rRef1, const BinSingleRef2d& rRef2, bool bDeleted, bool bRelativeAsOffset ) const
1227 {
1228     bool bSameSheet = rSheetRange.isSameSheet();
1229     initReference3d( orApiRef.Reference1, rSheetRange.getFirstSheet(), bSameSheet );
1230     initReference3d( orApiRef.Reference2, rSheetRange.getLastSheet(), bSameSheet );
1231     convertReference( orApiRef, rRef1, rRef2, bDeleted, bRelativeAsOffset );
1232     // remove sheet name from second part of reference
1233     setFlag( orApiRef.Reference2.Flags, SHEET_3D, rSheetRange.is3dRange() );
1234 }
1235 
1236 // finalize token sequence ----------------------------------------------------
1237 
1238 const FunctionInfo* FormulaParserImpl::resolveBadFuncName( const OUString& rTokenData ) const
1239 {
1240     /*  Try to parse calls to library functions. The format of such a function
1241         call is "[n]!funcname", n>0 being the link identifier of the function
1242         library spreadsheet file. */
1243     sal_Int32 nBracketOpen = rTokenData.indexOf( '[' );
1244     sal_Int32 nBracketClose = rTokenData.indexOf( ']' );
1245     sal_Int32 nExclamation = rTokenData.indexOf( '!' );
1246     if( (0 == nBracketOpen) && (nBracketOpen + 1 < nBracketClose) && (nBracketClose + 1 == nExclamation) && (nExclamation + 1 < rTokenData.getLength()) )
1247     {
1248         sal_Int32 nRefId = rTokenData.copy( nBracketOpen + 1, nBracketClose - nBracketOpen - 1 ).toInt32();
1249         const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get();
1250         if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_LIBRARY) )
1251         {
1252             OUString aFuncName = rTokenData.copy( nExclamation + 1 ).toAsciiUpperCase();
1253             if( const FunctionInfo* pFuncInfo = getFuncInfoFromOoxFuncName( aFuncName ) )
1254                 if( (pFuncInfo->meFuncLibType != FUNCLIB_UNKNOWN) && (pFuncInfo->meFuncLibType == pExtLink->getFuncLibraryType()) )
1255                     return pFuncInfo;
1256         }
1257     }
1258     return 0;
1259 }
1260 
1261 OUString FormulaParserImpl::resolveDefinedName( sal_Int32 nTokenIndex ) const
1262 {
1263     if( const DefinedName* pDefName = getDefinedNames().getByTokenIndex( nTokenIndex ).get() )
1264         return pDefName->getCalcName();
1265     return OUString();
1266 }
1267 
1268 // OOXML/BIFF12 parser implementation =========================================
1269 
1270 class OoxFormulaParserImpl : public FormulaParserImpl
1271 {
1272 public:
1273     explicit            OoxFormulaParserImpl( const FormulaParser& rParent );
1274 
1275     virtual ApiTokenSequence importOoxFormula(
1276                             const CellAddress& rBaseAddr,
1277                             const OUString& rFormulaString );
1278 
1279     virtual ApiTokenSequence importBiff12Formula(
1280                             const CellAddress& rBaseAddr,
1281                             FormulaType eType,
1282                             SequenceInputStream& rStrm );
1283 
1284 private:
1285     // import token contents and create API formula token ---------------------
1286 
1287     bool                importAttrToken( SequenceInputStream& rStrm );
1288     bool                importSpaceToken( SequenceInputStream& rStrm );
1289     bool                importTableToken( SequenceInputStream& rStrm );
1290     bool                importArrayToken( SequenceInputStream& rStrm );
1291     bool                importRefToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1292     bool                importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1293     bool                importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1294     bool                importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1295     bool                importMemAreaToken( SequenceInputStream& rStrm, bool bAddData );
1296     bool                importMemFuncToken( SequenceInputStream& rStrm );
1297     bool                importNameToken( SequenceInputStream& rStrm );
1298     bool                importNameXToken( SequenceInputStream& rStrm );
1299     bool                importFuncToken( SequenceInputStream& rStrm );
1300     bool                importFuncVarToken( SequenceInputStream& rStrm );
1301     bool                importExpToken( SequenceInputStream& rStrm );
1302 
1303     LinkSheetRange      readSheetRange( SequenceInputStream& rStrm );
1304 
1305     void                swapStreamPosition( SequenceInputStream& rStrm );
1306     void                skipMemAreaAddData( SequenceInputStream& rStrm );
1307 
1308     // convert BIN token and push API operand or operator ---------------------
1309 
1310     bool                pushBiff12Name( sal_Int32 nNameId );
1311     bool                pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId );
1312     bool                pushBiff12Function( sal_uInt16 nFuncId );
1313     bool                pushBiff12Function( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
1314 
1315 private:
1316     ApiParserWrapper    maApiParser;        /// Wrapper for the API formula parser object.
1317     sal_Int64           mnAddDataPos;       /// Current stream position for additional data (tExp, tArray, tMemArea).
1318     bool                mbNeedExtRefs;      /// True = parser needs initialization of external reference info.
1319 };
1320 
1321 // ----------------------------------------------------------------------------
1322 
1323 OoxFormulaParserImpl::OoxFormulaParserImpl( const FormulaParser& rParent ) :
1324     FormulaParserImpl( rParent ),
1325     maApiParser( rParent.getBaseFilter().getModelFactory(), rParent ),
1326     mnAddDataPos( 0 ),
1327     mbNeedExtRefs( true )
1328 {
1329 }
1330 
1331 ApiTokenSequence OoxFormulaParserImpl::importOoxFormula( const CellAddress& rBaseAddr, const OUString& rFormulaString )
1332 {
1333     if( mbNeedExtRefs )
1334     {
1335         maApiParser.getParserProperties().setProperty( PROP_ExternalLinks, getExternalLinks().getLinkInfos() );
1336         mbNeedExtRefs = false;
1337     }
1338     return finalizeTokenArray( maApiParser.parseFormula( rFormulaString, rBaseAddr ) );
1339 }
1340 
1341 ApiTokenSequence OoxFormulaParserImpl::importBiff12Formula( const CellAddress& rBaseAddr, FormulaType eType, SequenceInputStream& rStrm )
1342 {
1343     initializeImport( rBaseAddr, eType );
1344 
1345     sal_Int32 nFmlaSize = rStrm.readInt32();
1346     sal_Int64 nFmlaPos = rStrm.tell();
1347     sal_Int64 nFmlaEndPos = nFmlaPos + nFmlaSize;
1348 
1349     rStrm.seek( nFmlaEndPos );
1350     sal_Int32 nAddDataSize = rStrm.readInt32();
1351     mnAddDataPos = rStrm.tell();
1352     sal_Int64 nAddDataEndPos = mnAddDataPos + nAddDataSize;
1353     rStrm.seek( nFmlaPos );
1354 
1355     bool bOk = (nFmlaSize >= 0) && (nAddDataSize >= 0);
1356     bool bRelativeAsOffset = mbRelativeAsOffset;
1357 
1358     while( bOk && !rStrm.isEof() && (rStrm.tell() < nFmlaEndPos) )
1359     {
1360         sal_uInt8 nTokenId;
1361         rStrm >> nTokenId;
1362         sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
1363         sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
1364 
1365         if( nTokenClass == BIFF_TOKCLASS_NONE )
1366         {
1367             // base tokens
1368             switch( nBaseId )
1369             {
1370                 case BIFF_TOKID_EXP:        bOk = importExpToken( rStrm );                                      break;
1371                 case BIFF_TOKID_ADD:        bOk = pushBinaryOperator( OPCODE_ADD );                             break;
1372                 case BIFF_TOKID_SUB:        bOk = pushBinaryOperator( OPCODE_SUB );                             break;
1373                 case BIFF_TOKID_MUL:        bOk = pushBinaryOperator( OPCODE_MULT );                            break;
1374                 case BIFF_TOKID_DIV:        bOk = pushBinaryOperator( OPCODE_DIV );                             break;
1375                 case BIFF_TOKID_POWER:      bOk = pushBinaryOperator( OPCODE_POWER );                           break;
1376                 case BIFF_TOKID_CONCAT:     bOk = pushBinaryOperator( OPCODE_CONCAT );                          break;
1377                 case BIFF_TOKID_LT:         bOk = pushBinaryOperator( OPCODE_LESS );                            break;
1378                 case BIFF_TOKID_LE:         bOk = pushBinaryOperator( OPCODE_LESS_EQUAL );                      break;
1379                 case BIFF_TOKID_EQ:         bOk = pushBinaryOperator( OPCODE_EQUAL );                           break;
1380                 case BIFF_TOKID_GE:         bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL );                   break;
1381                 case BIFF_TOKID_GT:         bOk = pushBinaryOperator( OPCODE_GREATER );                         break;
1382                 case BIFF_TOKID_NE:         bOk = pushBinaryOperator( OPCODE_NOT_EQUAL );                       break;
1383                 case BIFF_TOKID_ISECT:      bOk = pushBinaryOperator( OPCODE_INTERSECT );                       break;
1384                 case BIFF_TOKID_LIST:       bOk = pushBinaryOperator( OPCODE_LIST );                            break;
1385                 case BIFF_TOKID_RANGE:      bOk = pushBinaryOperator( OPCODE_RANGE );                           break;
1386                 case BIFF_TOKID_UPLUS:      bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN );                     break;
1387                 case BIFF_TOKID_UMINUS:     bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN );                    break;
1388                 case BIFF_TOKID_PERCENT:    bOk = pushUnaryPostOperator( OPCODE_PERCENT );                      break;
1389                 case BIFF_TOKID_PAREN:      bOk = pushParenthesesOperator();                                    break;
1390                 case BIFF_TOKID_MISSARG:    bOk = pushOperand( OPCODE_MISSING );                                break;
1391                 case BIFF_TOKID_STR:        bOk = pushValueOperand( BiffHelper::readString( rStrm, false ) );   break;
1392                 case BIFF_TOKID_NLR:        bOk = importTableToken( rStrm );                                    break;
1393                 case BIFF_TOKID_ATTR:       bOk = importAttrToken( rStrm );                                     break;
1394                 case BIFF_TOKID_ERR:        bOk = pushBiffErrorOperand( rStrm.readuInt8() );                    break;
1395                 case BIFF_TOKID_BOOL:       bOk = pushBiffBoolOperand( rStrm.readuInt8() );                     break;
1396                 case BIFF_TOKID_INT:        bOk = pushValueOperand< double >( rStrm.readuInt16() );             break;
1397                 case BIFF_TOKID_NUM:        bOk = pushValueOperand( rStrm.readDouble() );                       break;
1398                 default:                    bOk = false;
1399             }
1400         }
1401         else
1402         {
1403             // classified tokens
1404             switch( nBaseId )
1405             {
1406                 case BIFF_TOKID_ARRAY:      bOk = importArrayToken( rStrm );                            break;
1407                 case BIFF_TOKID_FUNC:       bOk = importFuncToken( rStrm );                             break;
1408                 case BIFF_TOKID_FUNCVAR:    bOk = importFuncVarToken( rStrm );                          break;
1409                 case BIFF_TOKID_NAME:       bOk = importNameToken( rStrm );                             break;
1410                 case BIFF_TOKID_REF:        bOk = importRefToken( rStrm, false, false );                break;
1411                 case BIFF_TOKID_AREA:       bOk = importAreaToken( rStrm, false, false );               break;
1412                 case BIFF_TOKID_MEMAREA:    bOk = importMemAreaToken( rStrm, true );                    break;
1413                 case BIFF_TOKID_MEMERR:     bOk = importMemAreaToken( rStrm, false );                   break;
1414                 case BIFF_TOKID_MEMNOMEM:   bOk = importMemAreaToken( rStrm, false );                   break;
1415                 case BIFF_TOKID_MEMFUNC:    bOk = importMemFuncToken( rStrm );                          break;
1416                 case BIFF_TOKID_REFERR:     bOk = importRefToken( rStrm, true, false );                 break;
1417                 case BIFF_TOKID_AREAERR:    bOk = importAreaToken( rStrm, true, false );                break;
1418                 case BIFF_TOKID_REFN:       bOk = importRefToken( rStrm, false, true );                 break;
1419                 case BIFF_TOKID_AREAN:      bOk = importAreaToken( rStrm, false, true );                break;
1420                 case BIFF_TOKID_MEMAREAN:   bOk = importMemFuncToken( rStrm );                          break;
1421                 case BIFF_TOKID_MEMNOMEMN:  bOk = importMemFuncToken( rStrm );                          break;
1422                 case BIFF_TOKID_NAMEX:      bOk = importNameXToken( rStrm );                            break;
1423                 case BIFF_TOKID_REF3D:      bOk = importRef3dToken( rStrm, false, bRelativeAsOffset );  break;
1424                 case BIFF_TOKID_AREA3D:     bOk = importArea3dToken( rStrm, false, bRelativeAsOffset ); break;
1425                 case BIFF_TOKID_REFERR3D:   bOk = importRef3dToken( rStrm, true, bRelativeAsOffset );   break;
1426                 case BIFF_TOKID_AREAERR3D:  bOk = importArea3dToken( rStrm, true, bRelativeAsOffset );  break;
1427                 default:                    bOk = false;
1428             }
1429         }
1430     }
1431 
1432     // build and finalize the token sequence
1433     ApiTokenSequence aFinalTokens;
1434     if( bOk && (rStrm.tell() == nFmlaEndPos) && (mnAddDataPos == nAddDataEndPos) )
1435         aFinalTokens = finalizeImport();
1436 
1437     // seek behind token array
1438     if( (nFmlaSize >= 0) && (nAddDataSize >= 0) )
1439         rStrm.seek( nAddDataEndPos );
1440 
1441     // return the final token sequence
1442     return aFinalTokens;
1443 }
1444 
1445 // import token contents and create API formula token -------------------------
1446 
1447 bool OoxFormulaParserImpl::importAttrToken( SequenceInputStream& rStrm )
1448 {
1449     bool bOk = true;
1450     sal_uInt8 nType;
1451     rStrm >> nType;
1452     // equal flags in all BIFFs
1453     switch( nType )
1454     {
1455         case 0:     // sometimes, tAttrSkip tokens miss the type flag
1456         case BIFF_TOK_ATTR_VOLATILE:
1457         case BIFF_TOK_ATTR_IF:
1458         case BIFF_TOK_ATTR_SKIP:
1459         case BIFF_TOK_ATTR_ASSIGN:
1460         case BIFF_TOK_ATTR_IFERROR:
1461             rStrm.skip( 2 );
1462         break;
1463         case BIFF_TOK_ATTR_CHOOSE:
1464             rStrm.skip( 2 * rStrm.readuInt16() + 2 );
1465         break;
1466         case BIFF_TOK_ATTR_SUM:
1467             rStrm.skip( 2 );
1468             bOk = pushBiff12Function( BIFF_FUNC_SUM, 1 );
1469         break;
1470         case BIFF_TOK_ATTR_SPACE:
1471         case BIFF_TOK_ATTR_SPACE_VOLATILE:
1472             bOk = importSpaceToken( rStrm );
1473         break;
1474         default:
1475             bOk = false;
1476     }
1477     return bOk;
1478 }
1479 
1480 bool OoxFormulaParserImpl::importSpaceToken( SequenceInputStream& rStrm )
1481 {
1482     // equal constants in BIFF and OOX
1483     sal_uInt8 nType, nCount;
1484     rStrm >> nType >> nCount;
1485     switch( nType )
1486     {
1487         case BIFF_TOK_ATTR_SPACE_SP:
1488             appendLeadingSpaces( nCount, false );
1489         break;
1490         case BIFF_TOK_ATTR_SPACE_BR:
1491             appendLeadingSpaces( nCount, true );
1492         break;
1493         case BIFF_TOK_ATTR_SPACE_SP_OPEN:
1494             appendOpeningSpaces( nCount, false );
1495         break;
1496         case BIFF_TOK_ATTR_SPACE_BR_OPEN:
1497             appendOpeningSpaces( nCount, true );
1498         break;
1499         case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
1500             appendClosingSpaces( nCount, false );
1501         break;
1502         case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
1503             appendClosingSpaces( nCount, true );
1504         break;
1505     }
1506     return true;
1507 }
1508 
1509 bool OoxFormulaParserImpl::importTableToken( SequenceInputStream& rStrm )
1510 {
1511     sal_uInt16 nFlags, nTableId, nCol1, nCol2;
1512     rStrm.skip( 3 );
1513     rStrm >> nFlags >> nTableId;
1514     rStrm.skip( 2 );
1515     rStrm >> nCol1 >> nCol2;
1516     TableRef xTable = getTables().getTable( nTableId );
1517     sal_Int32 nTokenIndex = xTable.get() ? xTable->getTokenIndex() : -1;
1518     if( nTokenIndex >= 0 )
1519     {
1520         sal_Int32 nWidth = xTable->getWidth();
1521         sal_Int32 nHeight = xTable->getHeight();
1522         sal_Int32 nStartCol = 0;
1523         sal_Int32 nEndCol = nWidth - 1;
1524         sal_Int32 nStartRow = 0;
1525         sal_Int32 nEndRow = nHeight - 1;
1526         bool bFixedStartRow = true;
1527         bool bFixedHeight = false;
1528 
1529         bool bSingleCol = getFlag( nFlags, BIFF12_TOK_TABLE_COLUMN );
1530         bool bColRange = getFlag( nFlags, BIFF12_TOK_TABLE_COLRANGE );
1531         bool bValidRef = !bSingleCol || !bColRange;
1532         OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - illegal combination of single column and column range" );
1533         if( bValidRef )
1534         {
1535             if( bSingleCol )
1536                 nStartCol = nEndCol = nCol1;
1537             else if( bColRange )
1538                 { nStartCol = nCol1; nEndCol = nCol2; }
1539             bValidRef = (nStartCol <= nEndCol) && (nEndCol < nWidth);
1540             OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid column range" );
1541         }
1542 
1543         if( bValidRef )
1544         {
1545             bool bAllRows    = getFlag( nFlags, BIFF12_TOK_TABLE_ALL );
1546             bool bHeaderRows = getFlag( nFlags, BIFF12_TOK_TABLE_HEADERS );
1547             bool bDataRows   = getFlag( nFlags, BIFF12_TOK_TABLE_DATA );
1548             bool bTotalsRows = getFlag( nFlags, BIFF12_TOK_TABLE_TOTALS );
1549             bool bThisRow    = getFlag( nFlags, BIFF12_TOK_TABLE_THISROW );
1550 
1551             sal_Int32 nStartDataRow = xTable->getHeaderRows();
1552             sal_Int32 nEndDataRow = nEndRow - xTable->getTotalsRows();
1553             bValidRef = (nStartRow <= nStartDataRow) && (nStartDataRow <= nEndDataRow) && (nEndDataRow <= nEndRow);
1554             OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - invalid data row range" );
1555             if( bValidRef )
1556             {
1557                 if( bAllRows )
1558                 {
1559                     bValidRef = !bHeaderRows && !bDataRows && !bTotalsRows && !bThisRow;
1560                     OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#All] table token" );
1561                 }
1562                 else if( bHeaderRows )
1563                 {
1564                     bValidRef = !bTotalsRows && !bThisRow;
1565                     OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Headers] table token" );
1566                     nEndRow = bDataRows ? nEndDataRow : (nStartDataRow - 1);
1567                     bFixedHeight = !bDataRows;
1568                 }
1569                 else if( bDataRows )
1570                 {
1571                     bValidRef = !bThisRow;
1572                     OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Data] table token" );
1573                     nStartRow = nStartDataRow;
1574                     if( !bTotalsRows ) nEndRow = nEndDataRow;
1575                 }
1576                 else if( bTotalsRows )
1577                 {
1578                     bValidRef = !bThisRow;
1579                     OSL_ENSURE( bValidRef, "OoxFormulaParserImpl::importTableToken - unexpected flags in [#Totals] table token" );
1580                     nStartRow = nEndDataRow + 1;
1581                     bFixedStartRow = false;
1582                     bFixedHeight = !bDataRows;
1583                 }
1584                 else if( bThisRow )
1585                 {
1586                     nStartRow = nEndRow = maBaseAddr.Row - xTable->getRange().StartRow;
1587                     bFixedHeight = true;
1588                 }
1589                 else
1590                 {
1591                     // nothing is the same as [#Data]
1592                     nStartRow = nStartDataRow;
1593                     nEndRow = nEndDataRow;
1594                 }
1595             }
1596             if( bValidRef )
1597                 bValidRef = (0 <= nStartRow) && (nStartRow <= nEndRow) && (nEndRow < nHeight);
1598         }
1599         if( bValidRef )
1600         {
1601             // push single database area token, if table token refers to entire table
1602             if( (nStartCol == 0) && (nEndCol + 1 == nWidth) && (nStartRow == 0) && (nEndRow + 1 == nHeight) )
1603                 return pushValueOperand( nTokenIndex, OPCODE_DBAREA );
1604             // create an OFFSET function call to refer to a subrange of the table
1605             const FunctionInfo* pRowsInfo = getFuncInfoFromBiff12FuncId( BIFF_FUNC_ROWS );
1606             const FunctionInfo* pColumnsInfo = getFuncInfoFromBiff12FuncId( BIFF_FUNC_COLUMNS );
1607             return
1608                 pRowsInfo && pColumnsInfo &&
1609                 pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1610                 (bFixedStartRow ?
1611                     pushValueOperandToken< double >( nStartRow ) :
1612                     (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1613                      pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1614                      pushValueOperandToken< double >( nHeight - nStartRow ) &&
1615                      pushBinaryOperatorToken( OPCODE_SUB ))) &&
1616                 pushValueOperandToken< double >( nStartCol ) &&
1617                 (bFixedHeight ?
1618                     pushValueOperandToken< double >( nEndRow - nStartRow + 1 ) :
1619                     (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1620                      pushFunctionOperatorToken( *pRowsInfo, 1 ) &&
1621                      (((nStartRow == 0) && (nEndRow + 1 == nHeight)) ||
1622                       (pushValueOperandToken< double >( nHeight - (nEndRow - nStartRow + 1) ) &&
1623                        pushBinaryOperatorToken( OPCODE_SUB ))))) &&
1624                 (((nStartCol == 0) && (nEndCol + 1 == nWidth)) ?
1625                     (pushValueOperandToken( nTokenIndex, OPCODE_DBAREA ) &&
1626                      pushFunctionOperatorToken( *pColumnsInfo, 1 )) :
1627                     pushValueOperandToken< double >( nEndCol - nStartCol + 1 )) &&
1628                 pushBiff12Function( BIFF_FUNC_OFFSET, 5 );
1629         }
1630     }
1631     return pushBiffErrorOperand( BIFF_ERR_REF );
1632 }
1633 
1634 bool OoxFormulaParserImpl::importArrayToken( SequenceInputStream& rStrm )
1635 {
1636     rStrm.skip( 14 );
1637 
1638     // start token array with opening brace and leading spaces
1639     pushOperand( OPCODE_ARRAY_OPEN );
1640     size_t nOpSize = popOperandSize();
1641     size_t nOldArraySize = getFormulaSize();
1642 
1643     // read array size
1644     swapStreamPosition( rStrm );
1645     sal_Int32 nRows = rStrm.readInt32();
1646     sal_Int32 nCols = rStrm.readInt32();
1647     OSL_ENSURE( (nCols > 0) && (nRows > 0), "OoxFormulaParserImpl::importArrayToken - empty array" );
1648 
1649     // read array values and build token array
1650     for( sal_Int32 nRow = 0; !rStrm.isEof() && (nRow < nRows); ++nRow )
1651     {
1652         if( nRow > 0 )
1653             appendRawToken( OPCODE_ARRAY_ROWSEP );
1654         for( sal_Int32 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
1655         {
1656             if( nCol > 0 )
1657                 appendRawToken( OPCODE_ARRAY_COLSEP );
1658             switch( rStrm.readuInt8() )
1659             {
1660                 case BIFF_TOK_ARRAY_DOUBLE:
1661                     appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
1662                 break;
1663                 case BIFF_TOK_ARRAY_STRING:
1664                     appendRawToken( OPCODE_PUSH ) <<= BiffHelper::readString( rStrm, false );
1665                 break;
1666                 case BIFF_TOK_ARRAY_BOOL:
1667                     appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
1668                 break;
1669                 case BIFF_TOK_ARRAY_ERROR:
1670                     appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
1671                     rStrm.skip( 3 );
1672                 break;
1673                 default:
1674                     OSL_ENSURE( false, "OoxFormulaParserImpl::importArrayToken - unknown data type" );
1675                     appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
1676             }
1677         }
1678     }
1679     swapStreamPosition( rStrm );
1680 
1681     // close token array and set resulting operand size
1682     appendRawToken( OPCODE_ARRAY_CLOSE );
1683     pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
1684     return true;
1685 }
1686 
1687 bool OoxFormulaParserImpl::importRefToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1688 {
1689     BinSingleRef2d aRef;
1690     aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1691     return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1692 }
1693 
1694 bool OoxFormulaParserImpl::importAreaToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1695 {
1696     BinComplexRef2d aRef;
1697     aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1698     return pushReferenceOperand( aRef, bDeleted, bRelativeAsOffset );
1699 }
1700 
1701 bool OoxFormulaParserImpl::importRef3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1702 {
1703     LinkSheetRange aSheetRange = readSheetRange( rStrm );
1704     BinSingleRef2d aRef;
1705     aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1706     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1707 }
1708 
1709 bool OoxFormulaParserImpl::importArea3dToken( SequenceInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
1710 {
1711     LinkSheetRange aSheetRange = readSheetRange( rStrm );
1712     BinComplexRef2d aRef;
1713     aRef.readBiff12Data( rStrm, bRelativeAsOffset );
1714     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
1715 }
1716 
1717 bool OoxFormulaParserImpl::importMemAreaToken( SequenceInputStream& rStrm, bool bAddData )
1718 {
1719     rStrm.skip( 6 );
1720     if( bAddData )
1721         skipMemAreaAddData( rStrm );
1722     return true;
1723 }
1724 
1725 bool OoxFormulaParserImpl::importMemFuncToken( SequenceInputStream& rStrm )
1726 {
1727     rStrm.skip( 2 );
1728     return true;
1729 }
1730 
1731 bool OoxFormulaParserImpl::importNameToken( SequenceInputStream& rStrm )
1732 {
1733     return pushBiff12Name( rStrm.readInt32() );
1734 }
1735 
1736 bool OoxFormulaParserImpl::importNameXToken( SequenceInputStream& rStrm )
1737 {
1738     sal_Int32 nRefId = rStrm.readInt16();
1739     sal_Int32 nNameId = rStrm.readInt32();
1740     return pushBiff12ExtName( nRefId, nNameId );
1741 }
1742 
1743 bool OoxFormulaParserImpl::importFuncToken( SequenceInputStream& rStrm )
1744 {
1745     sal_uInt16 nFuncId;
1746     rStrm >> nFuncId;
1747     return pushBiff12Function( nFuncId );
1748 }
1749 
1750 bool OoxFormulaParserImpl::importFuncVarToken( SequenceInputStream& rStrm )
1751 {
1752     sal_uInt8 nParamCount;
1753     sal_uInt16 nFuncId;
1754     rStrm >> nParamCount >> nFuncId;
1755     return pushBiff12Function( nFuncId, nParamCount );
1756 }
1757 
1758 bool OoxFormulaParserImpl::importExpToken( SequenceInputStream& rStrm )
1759 {
1760     BinAddress aBaseAddr;
1761     rStrm >> aBaseAddr.mnRow;
1762     swapStreamPosition( rStrm );
1763     rStrm >> aBaseAddr.mnCol;
1764     swapStreamPosition( rStrm );
1765     return pushSpecialTokenOperand( aBaseAddr, false );
1766 }
1767 
1768 LinkSheetRange OoxFormulaParserImpl::readSheetRange( SequenceInputStream& rStrm )
1769 {
1770     return getExternalLinks().getSheetRange( rStrm.readInt16() );
1771 }
1772 
1773 void OoxFormulaParserImpl::swapStreamPosition( SequenceInputStream& rStrm )
1774 {
1775     sal_Int64 nRecPos = rStrm.tell();
1776     rStrm.seek( mnAddDataPos );
1777     mnAddDataPos = nRecPos;
1778 }
1779 
1780 void OoxFormulaParserImpl::skipMemAreaAddData( SequenceInputStream& rStrm )
1781 {
1782     swapStreamPosition( rStrm );
1783     rStrm.skip( 16 * rStrm.readInt32() );
1784     swapStreamPosition( rStrm );
1785 }
1786 
1787 // convert BIN token and push API operand or operator -------------------------
1788 
1789 bool OoxFormulaParserImpl::pushBiff12Name( sal_Int32 nNameId )
1790 {
1791     // one-based in BIFF12 formulas
1792     return pushDefinedNameOperand( getDefinedNames().getByIndex( nNameId - 1 ) );
1793 }
1794 
1795 bool OoxFormulaParserImpl::pushBiff12ExtName( sal_Int32 nRefId, sal_Int32 nNameId )
1796 {
1797     if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
1798     {
1799         if( pExtLink->getLinkType() == LINKTYPE_SELF )
1800             return pushBiff12Name( nNameId );
1801         // external name indexes are one-based in BIFF12
1802         ExternalNameRef xExtName = pExtLink->getNameByIndex( nNameId - 1 );
1803         return pushExternalNameOperand( xExtName, *pExtLink );
1804     }
1805     return pushBiffErrorOperand( BIFF_ERR_NAME );
1806 }
1807 
1808 bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId )
1809 {
1810     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( nFuncId ) )
1811         if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
1812             return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
1813     return pushFunctionOperator( OPCODE_NONAME, 0 );
1814 }
1815 
1816 bool OoxFormulaParserImpl::pushBiff12Function( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
1817 {
1818     if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
1819         nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
1820     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiff12FuncId( nFuncId ) )
1821         return pushFunctionOperator( *pFuncInfo, nParamCount );
1822     return pushFunctionOperator( OPCODE_NONAME, nParamCount );
1823 }
1824 
1825 // BIFF parser implementation =================================================
1826 
1827 namespace {
1828 
1829 /** A natural language reference struct with relative flag. */
1830 struct BiffNlr
1831 {
1832     sal_Int32           mnCol;              /// Column index.
1833     sal_Int32           mnRow;              /// Row index.
1834     bool                mbRel;              /// True = relative column/row reference.
1835 
1836     explicit            BiffNlr();
1837 
1838     void                readBiff8Data( BiffInputStream& rStrm );
1839 };
1840 
1841 BiffNlr::BiffNlr() :
1842     mnCol( 0 ),
1843     mnRow( 0 ),
1844     mbRel( false )
1845 {
1846 }
1847 
1848 void BiffNlr::readBiff8Data( BiffInputStream& rStrm )
1849 {
1850     sal_uInt16 nRow, nCol;
1851     rStrm >> nRow >> nCol;
1852     mnCol = nCol & BIFF_TOK_NLR_MASK;
1853     mnRow = nRow;
1854     mbRel = getFlag( nCol, BIFF_TOK_NLR_REL );
1855 }
1856 
1857 bool lclIsValidNlrStack( const BinAddress& rAddr1, const BinAddress& rAddr2, bool bRow )
1858 {
1859     return bRow ?
1860         ((rAddr1.mnRow == rAddr2.mnRow) && (rAddr1.mnCol + 1 == rAddr2.mnCol)) :
1861         ((rAddr1.mnCol == rAddr2.mnCol) && (rAddr1.mnRow + 1 == rAddr2.mnRow));
1862 }
1863 
1864 bool lclIsValidNlrRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
1865 {
1866     return bRow ?
1867         ((rNlr.mnRow == rRange.maFirst.mnRow) && (rNlr.mnCol + 1 == rRange.maFirst.mnCol) && (rRange.maFirst.mnRow == rRange.maLast.mnRow)) :
1868         ((rNlr.mnCol == rRange.maFirst.mnCol) && (rNlr.mnRow + 1 == rRange.maFirst.mnRow) && (rRange.maFirst.mnCol == rRange.maLast.mnCol));
1869 }
1870 
1871 } // namespace
1872 
1873 // ----------------------------------------------------------------------------
1874 
1875 class BiffFormulaParserImpl : public FormulaParserImpl
1876 {
1877 public:
1878     explicit            BiffFormulaParserImpl( const FormulaParser& rParent );
1879 
1880     virtual ApiTokenSequence importBiffFormula(
1881                             const CellAddress& rBaseAddr,
1882                             FormulaType eType,
1883                             BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize );
1884 
1885 private:
1886     // import token contents and create API formula token ---------------------
1887 
1888     bool                importTokenNotAvailable( BiffInputStream& rStrm );
1889     bool                importRefTokenNotAvailable( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1890     bool                importStrToken2( BiffInputStream& rStrm );
1891     bool                importStrToken8( BiffInputStream& rStrm );
1892     bool                importAttrToken( BiffInputStream& rStrm );
1893     bool                importSpaceToken3( BiffInputStream& rStrm );
1894     bool                importSpaceToken4( BiffInputStream& rStrm );
1895     bool                importSheetToken2( BiffInputStream& rStrm );
1896     bool                importSheetToken3( BiffInputStream& rStrm );
1897     bool                importEndSheetToken2( BiffInputStream& rStrm );
1898     bool                importEndSheetToken3( BiffInputStream& rStrm );
1899     bool                importNlrToken( BiffInputStream& rStrm );
1900     bool                importArrayToken( BiffInputStream& rStrm );
1901     bool                importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1902     bool                importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1903     bool                importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1904     bool                importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1905     bool                importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1906     bool                importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1907     bool                importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1908     bool                importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset );
1909     bool                importMemAreaToken( BiffInputStream& rStrm, bool bAddData );
1910     bool                importMemFuncToken( BiffInputStream& rStrm );
1911     bool                importNameToken( BiffInputStream& rStrm );
1912     bool                importNameXToken( BiffInputStream& rStrm );
1913     bool                importFuncToken2( BiffInputStream& rStrm );
1914     bool                importFuncToken4( BiffInputStream& rStrm );
1915     bool                importFuncVarToken2( BiffInputStream& rStrm );
1916     bool                importFuncVarToken4( BiffInputStream& rStrm );
1917     bool                importFuncCEToken( BiffInputStream& rStrm );
1918     bool                importExpToken( BiffInputStream& rStrm );
1919     bool                importTblToken( BiffInputStream& rStrm );
1920 
1921     bool                importNlrAddrToken( BiffInputStream& rStrm, bool bRow );
1922     bool                importNlrRangeToken( BiffInputStream& rStrm );
1923     bool                importNlrSAddrToken( BiffInputStream& rStrm, bool bRow );
1924     bool                importNlrSRangeToken( BiffInputStream& rStrm );
1925     bool                importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nSkip );
1926 
1927     sal_Int32           readRefId( BiffInputStream& rStrm );
1928     sal_uInt16          readNameId( BiffInputStream& rStrm );
1929     LinkSheetRange      readSheetRange5( BiffInputStream& rStrm );
1930     LinkSheetRange      readSheetRange8( BiffInputStream& rStrm );
1931 
1932     void                swapStreamPosition( BiffInputStream& rStrm );
1933     void                skipMemAreaAddData( BiffInputStream& rStrm );
1934     bool                readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow );
1935     bool                readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm );
1936 
1937     // convert BIFF token and push API operand or operator --------------------
1938 
1939     bool                pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
1940     bool                pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset );
1941     bool                pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow );
1942     bool                pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange );
1943     bool                pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow );
1944     bool                pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow );
1945     bool                pushBiffName( sal_uInt16 nNameId );
1946     bool                pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId );
1947     bool                pushBiffFunction( sal_uInt16 nFuncId );
1948     bool                pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount );
1949 
1950     // ------------------------------------------------------------------------
1951 private:
1952     typedef bool (BiffFormulaParserImpl::*ImportTokenFunc)( BiffInputStream& );
1953     typedef bool (BiffFormulaParserImpl::*ImportRefTokenFunc)( BiffInputStream&, bool, bool );
1954 
1955     ImportTokenFunc     mpImportStrToken;           /// Pointer to tStr import function (string constant).
1956     ImportTokenFunc     mpImportSpaceToken;         /// Pointer to tAttrSpace import function (spaces/line breaks).
1957     ImportTokenFunc     mpImportSheetToken;         /// Pointer to tSheet import function (external reference).
1958     ImportTokenFunc     mpImportEndSheetToken;      /// Pointer to tEndSheet import function (end of external reference).
1959     ImportTokenFunc     mpImportNlrToken;           /// Pointer to tNlr import function (natural language reference).
1960     ImportRefTokenFunc  mpImportRefToken;           /// Pointer to tRef import function (2d cell reference).
1961     ImportRefTokenFunc  mpImportAreaToken;          /// Pointer to tArea import function (2d area reference).
1962     ImportRefTokenFunc  mpImportRef3dToken;         /// Pointer to tRef3d import function (3d cell reference).
1963     ImportRefTokenFunc  mpImportArea3dToken;        /// Pointer to tArea3d import function (3d area reference).
1964     ImportTokenFunc     mpImportNameXToken;         /// Pointer to tNameX import function (external name).
1965     ImportTokenFunc     mpImportFuncToken;          /// Pointer to tFunc import function (function with fixed parameter count).
1966     ImportTokenFunc     mpImportFuncVarToken;       /// Pointer to tFuncVar import function (function with variable parameter count).
1967     ImportTokenFunc     mpImportFuncCEToken;        /// Pointer to tFuncCE import function (command macro call).
1968     sal_Int64           mnAddDataPos;               /// Current stream position for additional data (tArray, tMemArea, tNlr).
1969     sal_Int32           mnCurrRefId;                /// Current ref-id from tSheet token (BIFF2-BIFF4 only).
1970     sal_uInt16          mnAttrDataSize;             /// Size of one tAttr data element.
1971     sal_uInt16          mnArraySize;                /// Size of tArray data.
1972     sal_uInt16          mnNameSize;                 /// Size of tName data.
1973     sal_uInt16          mnMemAreaSize;              /// Size of tMemArea data.
1974     sal_uInt16          mnMemFuncSize;              /// Size of tMemFunc data.
1975     sal_uInt16          mnRefIdSize;                /// Size of unused data following a reference identifier.
1976 };
1977 
1978 // ----------------------------------------------------------------------------
1979 
1980 BiffFormulaParserImpl::BiffFormulaParserImpl( const FormulaParser& rParent ) :
1981     FormulaParserImpl( rParent ),
1982     mnAddDataPos( 0 ),
1983     mnCurrRefId( 0 )
1984 {
1985     switch( getBiff() )
1986     {
1987         case BIFF2:
1988             mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
1989             mpImportSpaceToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1990             mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken2;
1991             mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken2;
1992             mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1993             mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
1994             mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
1995             mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1996             mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
1997             mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
1998             mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
1999             mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
2000             mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
2001             mnAttrDataSize = 1;
2002             mnArraySize = 6;
2003             mnNameSize = 5;
2004             mnMemAreaSize = 4;
2005             mnMemFuncSize = 1;
2006             mnRefIdSize = 1;
2007         break;
2008         case BIFF3:
2009             mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
2010             mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken3;
2011             mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
2012             mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
2013             mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2014             mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
2015             mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
2016             mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2017             mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2018             mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2019             mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken2;
2020             mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken2;
2021             mpImportFuncCEToken = &BiffFormulaParserImpl::importFuncCEToken;
2022             mnAttrDataSize = 2;
2023             mnArraySize = 7;
2024             mnNameSize = 8;
2025             mnMemAreaSize = 6;
2026             mnMemFuncSize = 2;
2027             mnRefIdSize = 2;
2028         break;
2029         case BIFF4:
2030             mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
2031             mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2032             mpImportSheetToken = &BiffFormulaParserImpl::importSheetToken3;
2033             mpImportEndSheetToken = &BiffFormulaParserImpl::importEndSheetToken3;
2034             mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2035             mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
2036             mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
2037             mpImportRef3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2038             mpImportArea3dToken = &BiffFormulaParserImpl::importRefTokenNotAvailable;
2039             mpImportNameXToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2040             mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2041             mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2042             mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2043             mnAttrDataSize = 2;
2044             mnArraySize = 7;
2045             mnNameSize = 8;
2046             mnMemAreaSize = 6;
2047             mnMemFuncSize = 2;
2048             mnRefIdSize = 2;
2049         break;
2050         case BIFF5:
2051             mpImportStrToken = &BiffFormulaParserImpl::importStrToken2;
2052             mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2053             mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2054             mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2055             mpImportNlrToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2056             mpImportRefToken = &BiffFormulaParserImpl::importRefToken2;
2057             mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken2;
2058             mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken5;
2059             mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken5;
2060             mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
2061             mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2062             mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2063             mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2064             mnAttrDataSize = 2;
2065             mnArraySize = 7;
2066             mnNameSize = 12;
2067             mnMemAreaSize = 6;
2068             mnMemFuncSize = 2;
2069             mnRefIdSize = 8;
2070         break;
2071         case BIFF8:
2072             mpImportStrToken = &BiffFormulaParserImpl::importStrToken8;
2073             mpImportSpaceToken = &BiffFormulaParserImpl::importSpaceToken4;
2074             mpImportSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2075             mpImportEndSheetToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2076             mpImportNlrToken = &BiffFormulaParserImpl::importNlrToken;
2077             mpImportRefToken = &BiffFormulaParserImpl::importRefToken8;
2078             mpImportAreaToken = &BiffFormulaParserImpl::importAreaToken8;
2079             mpImportRef3dToken = &BiffFormulaParserImpl::importRef3dToken8;
2080             mpImportArea3dToken = &BiffFormulaParserImpl::importArea3dToken8;
2081             mpImportNameXToken = &BiffFormulaParserImpl::importNameXToken;
2082             mpImportFuncToken = &BiffFormulaParserImpl::importFuncToken4;
2083             mpImportFuncVarToken = &BiffFormulaParserImpl::importFuncVarToken4;
2084             mpImportFuncCEToken = &BiffFormulaParserImpl::importTokenNotAvailable;
2085             mnAttrDataSize = 2;
2086             mnArraySize = 7;
2087             mnNameSize = 2;
2088             mnMemAreaSize = 6;
2089             mnMemFuncSize = 2;
2090             mnRefIdSize = 0;
2091         break;
2092         case BIFF_UNKNOWN: break;
2093     }
2094 }
2095 
2096 ApiTokenSequence BiffFormulaParserImpl::importBiffFormula( const CellAddress& rBaseAddr,
2097         FormulaType eType, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
2098 {
2099     initializeImport( rBaseAddr, eType );
2100     mnCurrRefId = 0;
2101 
2102     sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
2103     sal_Int64 nEndPos = mnAddDataPos = rStrm.tell() + nFmlaSize;
2104 
2105     bool bOk = true;
2106     while( bOk && !rStrm.isEof() && (rStrm.tell() < nEndPos) )
2107     {
2108         sal_uInt8 nTokenId;
2109         rStrm >> nTokenId;
2110         sal_uInt8 nTokenClass = nTokenId & BIFF_TOKCLASS_MASK;
2111         sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
2112 
2113         bOk = !getFlag( nTokenId, BIFF_TOKFLAG_INVALID );
2114         if( bOk )
2115         {
2116             if( nTokenClass == BIFF_TOKCLASS_NONE )
2117             {
2118                 // base tokens
2119                 switch( nBaseId )
2120                 {
2121                     case BIFF_TOKID_EXP:        bOk = importExpToken( rStrm );                          break;
2122                     case BIFF_TOKID_TBL:        bOk = importTblToken( rStrm );                          break;
2123                     case BIFF_TOKID_ADD:        bOk = pushBinaryOperator( OPCODE_ADD );                 break;
2124                     case BIFF_TOKID_SUB:        bOk = pushBinaryOperator( OPCODE_SUB );                 break;
2125                     case BIFF_TOKID_MUL:        bOk = pushBinaryOperator( OPCODE_MULT );                break;
2126                     case BIFF_TOKID_DIV:        bOk = pushBinaryOperator( OPCODE_DIV );                 break;
2127                     case BIFF_TOKID_POWER:      bOk = pushBinaryOperator( OPCODE_POWER );               break;
2128                     case BIFF_TOKID_CONCAT:     bOk = pushBinaryOperator( OPCODE_CONCAT );              break;
2129                     case BIFF_TOKID_LT:         bOk = pushBinaryOperator( OPCODE_LESS );                break;
2130                     case BIFF_TOKID_LE:         bOk = pushBinaryOperator( OPCODE_LESS_EQUAL );          break;
2131                     case BIFF_TOKID_EQ:         bOk = pushBinaryOperator( OPCODE_EQUAL );               break;
2132                     case BIFF_TOKID_GE:         bOk = pushBinaryOperator( OPCODE_GREATER_EQUAL );       break;
2133                     case BIFF_TOKID_GT:         bOk = pushBinaryOperator( OPCODE_GREATER );             break;
2134                     case BIFF_TOKID_NE:         bOk = pushBinaryOperator( OPCODE_NOT_EQUAL );           break;
2135                     case BIFF_TOKID_ISECT:      bOk = pushBinaryOperator( OPCODE_INTERSECT );           break;
2136                     case BIFF_TOKID_LIST:       bOk = pushBinaryOperator( OPCODE_LIST );                break;
2137                     case BIFF_TOKID_RANGE:      bOk = pushBinaryOperator( OPCODE_RANGE );               break;
2138                     case BIFF_TOKID_UPLUS:      bOk = pushUnaryPreOperator( OPCODE_PLUS_SIGN );         break;
2139                     case BIFF_TOKID_UMINUS:     bOk = pushUnaryPreOperator( OPCODE_MINUS_SIGN );        break;
2140                     case BIFF_TOKID_PERCENT:    bOk = pushUnaryPostOperator( OPCODE_PERCENT );          break;
2141                     case BIFF_TOKID_PAREN:      bOk = pushParenthesesOperator();                        break;
2142                     case BIFF_TOKID_MISSARG:    bOk = pushOperand( OPCODE_MISSING );                    break;
2143                     case BIFF_TOKID_STR:        bOk = (this->*mpImportStrToken)( rStrm );               break;
2144                     case BIFF_TOKID_NLR:        bOk = (this->*mpImportNlrToken)( rStrm );               break;
2145                     case BIFF_TOKID_ATTR:       bOk = importAttrToken( rStrm );                         break;
2146                     case BIFF_TOKID_SHEET:      bOk = (this->*mpImportSheetToken)( rStrm );             break;
2147                     case BIFF_TOKID_ENDSHEET:   bOk = (this->*mpImportEndSheetToken)( rStrm );          break;
2148                     case BIFF_TOKID_ERR:        bOk = pushBiffErrorOperand( rStrm.readuInt8() );        break;
2149                     case BIFF_TOKID_BOOL:       bOk = pushBiffBoolOperand( rStrm.readuInt8() );         break;
2150                     case BIFF_TOKID_INT:        bOk = pushValueOperand< double >( rStrm.readuInt16() ); break;
2151                     case BIFF_TOKID_NUM:        bOk = pushValueOperand( rStrm.readDouble() );           break;
2152                     default:                    bOk = false;
2153                 }
2154             }
2155             else
2156             {
2157                 // classified tokens
2158                 switch( nBaseId )
2159                 {
2160                     case BIFF_TOKID_ARRAY:      bOk = importArrayToken( rStrm );                                        break;
2161                     case BIFF_TOKID_FUNC:       bOk = (this->*mpImportFuncToken)( rStrm );                              break;
2162                     case BIFF_TOKID_FUNCVAR:    bOk = (this->*mpImportFuncVarToken)( rStrm );                           break;
2163                     case BIFF_TOKID_NAME:       bOk = importNameToken( rStrm );                                         break;
2164                     case BIFF_TOKID_REF:        bOk = (this->*mpImportRefToken)( rStrm, false, false );                 break;
2165                     case BIFF_TOKID_AREA:       bOk = (this->*mpImportAreaToken)( rStrm, false, false );                break;
2166                     case BIFF_TOKID_MEMAREA:    bOk = importMemAreaToken( rStrm, true );                                break;
2167                     case BIFF_TOKID_MEMERR:     bOk = importMemAreaToken( rStrm, false );                               break;
2168                     case BIFF_TOKID_MEMNOMEM:   bOk = importMemAreaToken( rStrm, false );                               break;
2169                     case BIFF_TOKID_MEMFUNC:    bOk = importMemFuncToken( rStrm );                                      break;
2170                     case BIFF_TOKID_REFERR:     bOk = (this->*mpImportRefToken)( rStrm, true, false );                  break;
2171                     case BIFF_TOKID_AREAERR:    bOk = (this->*mpImportAreaToken)( rStrm, true, false );                 break;
2172                     case BIFF_TOKID_REFN:       bOk = (this->*mpImportRefToken)( rStrm, false, true );                  break;
2173                     case BIFF_TOKID_AREAN:      bOk = (this->*mpImportAreaToken)( rStrm, false, true );                 break;
2174                     case BIFF_TOKID_MEMAREAN:   bOk = importMemFuncToken( rStrm );                                      break;
2175                     case BIFF_TOKID_MEMNOMEMN:  bOk = importMemFuncToken( rStrm );                                      break;
2176                     case BIFF_TOKID_FUNCCE:     bOk = (this->*mpImportFuncCEToken)( rStrm );                            break;
2177                     case BIFF_TOKID_NAMEX:      bOk = (this->*mpImportNameXToken)( rStrm );                             break;
2178                     case BIFF_TOKID_REF3D:      bOk = (this->*mpImportRef3dToken)( rStrm, false, mbRelativeAsOffset );  break;
2179                     case BIFF_TOKID_AREA3D:     bOk = (this->*mpImportArea3dToken)( rStrm, false, mbRelativeAsOffset ); break;
2180                     case BIFF_TOKID_REFERR3D:   bOk = (this->*mpImportRef3dToken)( rStrm, true, mbRelativeAsOffset );   break;
2181                     case BIFF_TOKID_AREAERR3D:  bOk = (this->*mpImportArea3dToken)( rStrm, true, mbRelativeAsOffset );  break;
2182                     default:                    bOk = false;
2183                 }
2184             }
2185         }
2186     }
2187 
2188     // build and finalize the token sequence
2189     ApiTokenSequence aFinalTokens;
2190     if( bOk && (rStrm.tell() == nEndPos) )
2191         aFinalTokens = finalizeImport();
2192 
2193     // seek behind additional token data of tArray, tMemArea, tNlr tokens
2194     rStrm.seek( mnAddDataPos );
2195 
2196     // return the final token sequence
2197     return aFinalTokens;
2198 }
2199 
2200 // import token contents and create API formula token -------------------------
2201 
2202 bool BiffFormulaParserImpl::importTokenNotAvailable( BiffInputStream& )
2203 {
2204     // dummy function for pointer-to-member-function
2205     return false;
2206 }
2207 
2208 bool BiffFormulaParserImpl::importRefTokenNotAvailable( BiffInputStream&, bool, bool )
2209 {
2210     // dummy function for pointer-to-member-function
2211     return false;
2212 }
2213 
2214 bool BiffFormulaParserImpl::importStrToken2( BiffInputStream& rStrm )
2215 {
2216     return pushValueOperand( rStrm.readByteStringUC( false, getTextEncoding(), mbAllowNulChars ) );
2217 }
2218 
2219 bool BiffFormulaParserImpl::importStrToken8( BiffInputStream& rStrm )
2220 {
2221     // read flags field for empty strings also
2222     return pushValueOperand( rStrm.readUniStringBody( rStrm.readuInt8(), mbAllowNulChars ) );
2223 }
2224 
2225 bool BiffFormulaParserImpl::importAttrToken( BiffInputStream& rStrm )
2226 {
2227     bool bOk = true;
2228     sal_uInt8 nType;
2229     rStrm >> nType;
2230     switch( nType )
2231     {
2232         case 0:     // sometimes, tAttrSkip tokens miss the type flag
2233         case BIFF_TOK_ATTR_VOLATILE:
2234         case BIFF_TOK_ATTR_IF:
2235         case BIFF_TOK_ATTR_SKIP:
2236         case BIFF_TOK_ATTR_ASSIGN:
2237             rStrm.skip( mnAttrDataSize );
2238         break;
2239         case BIFF_TOK_ATTR_CHOOSE:
2240             rStrm.skip( mnAttrDataSize * (1 + ((getBiff() == BIFF2) ? rStrm.readuInt8() : rStrm.readuInt16())) );
2241         break;
2242         case BIFF_TOK_ATTR_SUM:
2243             rStrm.skip( mnAttrDataSize );
2244             bOk = pushBiffFunction( BIFF_FUNC_SUM, 1 );
2245         break;
2246         case BIFF_TOK_ATTR_SPACE:
2247         case BIFF_TOK_ATTR_SPACE_VOLATILE:
2248             bOk = (this->*mpImportSpaceToken)( rStrm );
2249         break;
2250         default:
2251             bOk = false;
2252     }
2253     return bOk;
2254 }
2255 
2256 bool BiffFormulaParserImpl::importSpaceToken3( BiffInputStream& rStrm )
2257 {
2258     rStrm.skip( 2 );
2259     return true;
2260 }
2261 
2262 bool BiffFormulaParserImpl::importSpaceToken4( BiffInputStream& rStrm )
2263 {
2264     sal_uInt8 nType, nCount;
2265     rStrm >> nType >> nCount;
2266     switch( nType )
2267     {
2268         case BIFF_TOK_ATTR_SPACE_SP:
2269             appendLeadingSpaces( nCount, false );
2270         break;
2271         case BIFF_TOK_ATTR_SPACE_BR:
2272             appendLeadingSpaces( nCount, true );
2273         break;
2274         case BIFF_TOK_ATTR_SPACE_SP_OPEN:
2275             appendOpeningSpaces( nCount, false );
2276         break;
2277         case BIFF_TOK_ATTR_SPACE_BR_OPEN:
2278             appendOpeningSpaces( nCount, true );
2279         break;
2280         case BIFF_TOK_ATTR_SPACE_SP_CLOSE:
2281             appendClosingSpaces( nCount, false );
2282         break;
2283         case BIFF_TOK_ATTR_SPACE_BR_CLOSE:
2284             appendClosingSpaces( nCount, true );
2285         break;
2286     }
2287     return true;
2288 }
2289 
2290 bool BiffFormulaParserImpl::importSheetToken2( BiffInputStream& rStrm )
2291 {
2292     rStrm.skip( 4 );
2293     mnCurrRefId = readRefId( rStrm );
2294     return true;
2295 }
2296 
2297 bool BiffFormulaParserImpl::importSheetToken3( BiffInputStream& rStrm )
2298 {
2299     rStrm.skip( 6 );
2300     mnCurrRefId = readRefId( rStrm );
2301     return true;
2302 }
2303 
2304 bool BiffFormulaParserImpl::importEndSheetToken2( BiffInputStream& rStrm )
2305 {
2306     rStrm.skip( 3 );
2307     mnCurrRefId = 0;
2308     return true;
2309 }
2310 
2311 bool BiffFormulaParserImpl::importEndSheetToken3( BiffInputStream& rStrm )
2312 {
2313     rStrm.skip( 4 );
2314     mnCurrRefId = 0;
2315     return true;
2316 }
2317 
2318 bool BiffFormulaParserImpl::importNlrToken( BiffInputStream& rStrm )
2319 {
2320     bool bOk = true;
2321     sal_uInt8 nNlrType;
2322     rStrm >> nNlrType;
2323     switch( nNlrType )
2324     {
2325         case BIFF_TOK_NLR_ERR:      bOk = importNlrErrToken( rStrm, 4 );        break;
2326         case BIFF_TOK_NLR_ROWR:     bOk = importNlrAddrToken( rStrm, true );    break;
2327         case BIFF_TOK_NLR_COLR:     bOk = importNlrAddrToken( rStrm, false );   break;
2328         case BIFF_TOK_NLR_ROWV:     bOk = importNlrAddrToken( rStrm, true );    break;
2329         case BIFF_TOK_NLR_COLV:     bOk = importNlrAddrToken( rStrm, false );   break;
2330         case BIFF_TOK_NLR_RANGE:    bOk = importNlrRangeToken( rStrm );         break;
2331         case BIFF_TOK_NLR_SRANGE:   bOk = importNlrSRangeToken( rStrm );        break;
2332         case BIFF_TOK_NLR_SROWR:    bOk = importNlrSAddrToken( rStrm, true );   break;
2333         case BIFF_TOK_NLR_SCOLR:    bOk = importNlrSAddrToken( rStrm, false );  break;
2334         case BIFF_TOK_NLR_SROWV:    bOk = importNlrSAddrToken( rStrm, true );   break;
2335         case BIFF_TOK_NLR_SCOLV:    bOk = importNlrSAddrToken( rStrm, false );  break;
2336         case BIFF_TOK_NLR_RANGEERR: bOk = importNlrErrToken( rStrm, 13 );       break;
2337         case BIFF_TOK_NLR_SXNAME:   bOk = importNlrErrToken( rStrm, 4 );        break;
2338         default:                    bOk = false;
2339     }
2340     return bOk;
2341 }
2342 
2343 bool BiffFormulaParserImpl::importArrayToken( BiffInputStream& rStrm )
2344 {
2345     rStrm.skip( mnArraySize );
2346 
2347     // start token array with opening brace and leading spaces
2348     pushOperand( OPCODE_ARRAY_OPEN );
2349     size_t nOpSize = popOperandSize();
2350     size_t nOldArraySize = getFormulaSize();
2351     bool bBiff8 = getBiff() == BIFF8;
2352 
2353     // read array size
2354     swapStreamPosition( rStrm );
2355     sal_uInt16 nCols = rStrm.readuInt8();
2356     sal_uInt16 nRows = rStrm.readuInt16();
2357     if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
2358     OSL_ENSURE( (nCols > 0) && (nRows > 0), "BiffFormulaParserImpl::importArrayToken - empty array" );
2359 
2360     // read array values and build token array
2361     for( sal_uInt16 nRow = 0; !rStrm.isEof() && (nRow < nRows); ++nRow )
2362     {
2363         if( nRow > 0 )
2364             appendRawToken( OPCODE_ARRAY_ROWSEP );
2365         for( sal_uInt16 nCol = 0; !rStrm.isEof() && (nCol < nCols); ++nCol )
2366         {
2367             if( nCol > 0 )
2368                 appendRawToken( OPCODE_ARRAY_COLSEP );
2369             switch( rStrm.readuInt8() )
2370             {
2371                 case BIFF_DATATYPE_EMPTY:
2372                     appendRawToken( OPCODE_PUSH ) <<= OUString();
2373                     rStrm.skip( 8 );
2374                 break;
2375                 case BIFF_DATATYPE_DOUBLE:
2376                     appendRawToken( OPCODE_PUSH ) <<= rStrm.readDouble();
2377                 break;
2378                 case BIFF_DATATYPE_STRING:
2379                     appendRawToken( OPCODE_PUSH ) <<= bBiff8 ?
2380                         rStrm.readUniString( mbAllowNulChars ) :
2381                         rStrm.readByteStringUC( false, getTextEncoding(), mbAllowNulChars );
2382                 break;
2383                 case BIFF_DATATYPE_BOOL:
2384                     appendRawToken( OPCODE_PUSH ) <<= static_cast< double >( (rStrm.readuInt8() == BIFF_TOK_BOOL_FALSE) ? 0.0 : 1.0 );
2385                     rStrm.skip( 7 );
2386                 break;
2387                 case BIFF_DATATYPE_ERROR:
2388                     appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( rStrm.readuInt8() );
2389                     rStrm.skip( 7 );
2390                 break;
2391                 default:
2392                     OSL_ENSURE( false, "BiffFormulaParserImpl::importArrayToken - unknown data type" );
2393                     appendRawToken( OPCODE_PUSH ) <<= BiffHelper::calcDoubleFromError( BIFF_ERR_NA );
2394             }
2395         }
2396     }
2397     swapStreamPosition( rStrm );
2398 
2399     // close token array and set resulting operand size
2400     appendRawToken( OPCODE_ARRAY_CLOSE );
2401     pushOperandSize( nOpSize + getFormulaSize() - nOldArraySize );
2402     return true;
2403 }
2404 
2405 bool BiffFormulaParserImpl::importRefToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2406 {
2407     BinSingleRef2d aRef;
2408     aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2409     return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2410 }
2411 
2412 bool BiffFormulaParserImpl::importRefToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2413 {
2414     BinSingleRef2d aRef;
2415     aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2416     return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2417 }
2418 
2419 bool BiffFormulaParserImpl::importAreaToken2( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2420 {
2421     BinComplexRef2d aRef;
2422     aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2423     return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2424 }
2425 
2426 bool BiffFormulaParserImpl::importAreaToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2427 {
2428     BinComplexRef2d aRef;
2429     aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2430     return pushBiffReference( aRef, bDeleted, bRelativeAsOffset );
2431 }
2432 
2433 bool BiffFormulaParserImpl::importRef3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2434 {
2435     LinkSheetRange aSheetRange = readSheetRange5( rStrm );
2436     BinSingleRef2d aRef;
2437     aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2438     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2439 }
2440 
2441 bool BiffFormulaParserImpl::importRef3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2442 {
2443     LinkSheetRange aSheetRange = readSheetRange8( rStrm );
2444     BinSingleRef2d aRef;
2445     aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2446     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2447 }
2448 
2449 bool BiffFormulaParserImpl::importArea3dToken5( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2450 {
2451     LinkSheetRange aSheetRange = readSheetRange5( rStrm );
2452     BinComplexRef2d aRef;
2453     aRef.readBiff2Data( rStrm, bRelativeAsOffset );
2454     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2455 }
2456 
2457 bool BiffFormulaParserImpl::importArea3dToken8( BiffInputStream& rStrm, bool bDeleted, bool bRelativeAsOffset )
2458 {
2459     LinkSheetRange aSheetRange = readSheetRange8( rStrm );
2460     BinComplexRef2d aRef;
2461     aRef.readBiff8Data( rStrm, bRelativeAsOffset );
2462     return pushReferenceOperand( aSheetRange, aRef, bDeleted, bRelativeAsOffset );
2463 }
2464 
2465 bool BiffFormulaParserImpl::importMemAreaToken( BiffInputStream& rStrm, bool bAddData )
2466 {
2467     rStrm.skip( mnMemAreaSize );
2468     if( bAddData )
2469         skipMemAreaAddData( rStrm );
2470     return true;
2471 }
2472 
2473 bool BiffFormulaParserImpl::importMemFuncToken( BiffInputStream& rStrm )
2474 {
2475     rStrm.skip( mnMemFuncSize );
2476     return true;
2477 }
2478 
2479 bool BiffFormulaParserImpl::importNameToken( BiffInputStream& rStrm )
2480 {
2481     sal_uInt16 nNameId = readNameId( rStrm );
2482     return (mnCurrRefId > 0) ? pushBiffExtName( mnCurrRefId, nNameId ) : pushBiffName( nNameId );
2483 }
2484 
2485 bool BiffFormulaParserImpl::importNameXToken( BiffInputStream& rStrm )
2486 {
2487     sal_Int32 nRefId = readRefId( rStrm );
2488     sal_uInt16 nNameId = readNameId( rStrm );
2489     return pushBiffExtName( nRefId, nNameId );
2490 }
2491 
2492 bool BiffFormulaParserImpl::importFuncToken2( BiffInputStream& rStrm )
2493 {
2494     sal_uInt8 nFuncId;
2495     rStrm >> nFuncId;
2496     return pushBiffFunction( nFuncId );
2497 }
2498 
2499 bool BiffFormulaParserImpl::importFuncToken4( BiffInputStream& rStrm )
2500 {
2501     sal_uInt16 nFuncId;
2502     rStrm >> nFuncId;
2503     return pushBiffFunction( nFuncId );
2504 }
2505 
2506 bool BiffFormulaParserImpl::importFuncVarToken2( BiffInputStream& rStrm )
2507 {
2508     sal_uInt8 nParamCount, nFuncId;
2509     rStrm >> nParamCount >> nFuncId;
2510     return pushBiffFunction( nFuncId, nParamCount );
2511 }
2512 
2513 bool BiffFormulaParserImpl::importFuncVarToken4( BiffInputStream& rStrm )
2514 {
2515     sal_uInt8 nParamCount;
2516     sal_uInt16 nFuncId;
2517     rStrm >> nParamCount >> nFuncId;
2518     return pushBiffFunction( nFuncId, nParamCount & BIFF_TOK_FUNCVAR_COUNTMASK );
2519 }
2520 
2521 bool BiffFormulaParserImpl::importFuncCEToken( BiffInputStream& rStrm )
2522 {
2523     sal_uInt8 nParamCount, nFuncId;
2524     rStrm >> nParamCount >> nFuncId;
2525     sal_uInt16 nCmdId = nFuncId;
2526     setFlag( nCmdId, BIFF_TOK_FUNCVAR_CMD );
2527     return pushBiffFunction( nCmdId, nParamCount );
2528 }
2529 
2530 bool BiffFormulaParserImpl::importExpToken( BiffInputStream& rStrm )
2531 {
2532     BinAddress aBaseAddr;
2533     aBaseAddr.read( rStrm );
2534     return pushSpecialTokenOperand( aBaseAddr, false );
2535 }
2536 
2537 bool BiffFormulaParserImpl::importTblToken( BiffInputStream& rStrm )
2538 {
2539     BinAddress aBaseAddr;
2540     aBaseAddr.read( rStrm );
2541     return pushSpecialTokenOperand( aBaseAddr, true );
2542 }
2543 
2544 bool BiffFormulaParserImpl::importNlrAddrToken( BiffInputStream& rStrm, bool bRow )
2545 {
2546     BiffNlr aNlr;
2547     aNlr.readBiff8Data( rStrm );
2548     return pushBiffNlrAddr( aNlr, bRow );
2549 }
2550 
2551 bool BiffFormulaParserImpl::importNlrRangeToken( BiffInputStream& rStrm )
2552 {
2553     BiffNlr aNlr;
2554     aNlr.readBiff8Data( rStrm );
2555     rStrm.skip( 1 );
2556     BinRange aRange;
2557     rStrm >> aRange;
2558     return pushBiffNlrRange( aNlr, aRange );
2559 }
2560 
2561 bool BiffFormulaParserImpl::importNlrSAddrToken( BiffInputStream& rStrm, bool bRow )
2562 {
2563     rStrm.skip( 4 );
2564     BiffNlr aNlr;
2565     return readNlrSAddrAddData( aNlr, rStrm, bRow ) ? pushBiffNlrSAddr( aNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2566 }
2567 
2568 bool BiffFormulaParserImpl::importNlrSRangeToken( BiffInputStream& rStrm )
2569 {
2570     rStrm.skip( 5 );
2571     BinRange aRange;
2572     rStrm >> aRange;
2573     BiffNlr aNlr;
2574     bool bRow;
2575     return readNlrSRangeAddData( aNlr, bRow, rStrm ) ? pushBiffNlrSRange( aNlr, aRange, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2576 }
2577 
2578 bool BiffFormulaParserImpl::importNlrErrToken( BiffInputStream& rStrm, sal_uInt16 nIgnore )
2579 {
2580     rStrm.skip( nIgnore );
2581     return pushBiffErrorOperand( BIFF_ERR_NAME );
2582 }
2583 
2584 sal_Int32 BiffFormulaParserImpl::readRefId( BiffInputStream& rStrm )
2585 {
2586     sal_Int16 nRefId;
2587     rStrm >> nRefId;
2588     rStrm.skip( mnRefIdSize );
2589     return nRefId;
2590 }
2591 
2592 sal_uInt16 BiffFormulaParserImpl::readNameId( BiffInputStream& rStrm )
2593 {
2594     sal_uInt16 nNameId;
2595     rStrm >> nNameId;
2596     rStrm.skip( mnNameSize );
2597     return nNameId;
2598 }
2599 
2600 LinkSheetRange BiffFormulaParserImpl::readSheetRange5( BiffInputStream& rStrm )
2601 {
2602     sal_Int32 nRefId = readRefId( rStrm );
2603     sal_Int16 nTab1, nTab2;
2604     rStrm >> nTab1 >> nTab2;
2605     return getExternalLinks().getSheetRange( nRefId, nTab1, nTab2 );
2606 }
2607 
2608 LinkSheetRange BiffFormulaParserImpl::readSheetRange8( BiffInputStream& rStrm )
2609 {
2610     return getExternalLinks().getSheetRange( readRefId( rStrm ) );
2611 }
2612 
2613 void BiffFormulaParserImpl::swapStreamPosition( BiffInputStream& rStrm )
2614 {
2615     sal_Int64 nRecPos = rStrm.tell();
2616     rStrm.seek( mnAddDataPos );
2617     mnAddDataPos = nRecPos;
2618 }
2619 
2620 void BiffFormulaParserImpl::skipMemAreaAddData( BiffInputStream& rStrm )
2621 {
2622     swapStreamPosition( rStrm );
2623     sal_Int32 nCount = rStrm.readuInt16();
2624     rStrm.skip( ((getBiff() == BIFF8) ? 8 : 6) * nCount );
2625     swapStreamPosition( rStrm );
2626 }
2627 
2628 bool BiffFormulaParserImpl::readNlrSAddrAddData( BiffNlr& orNlr, BiffInputStream& rStrm, bool bRow )
2629 {
2630     bool bIsRow;
2631     return readNlrSRangeAddData( orNlr, bIsRow, rStrm ) && (bIsRow == bRow);
2632 }
2633 
2634 bool BiffFormulaParserImpl::readNlrSRangeAddData( BiffNlr& orNlr, bool& orbIsRow, BiffInputStream& rStrm )
2635 {
2636     swapStreamPosition( rStrm );
2637     // read number of cell addresses and relative flag
2638     sal_uInt32 nCount;
2639     rStrm >> nCount;
2640     bool bRel = getFlag( nCount, BIFF_TOK_NLR_ADDREL );
2641     nCount &= BIFF_TOK_NLR_ADDMASK;
2642     sal_Int64 nEndPos = rStrm.tell() + 4 * nCount;
2643     // read list of cell addresses
2644     bool bValid = false;
2645     if( nCount >= 2 )
2646     {
2647         // detect column/row orientation
2648         BinAddress aAddr1, aAddr2;
2649         rStrm >> aAddr1 >> aAddr2;
2650         orbIsRow = aAddr1.mnRow == aAddr2.mnRow;
2651         bValid = lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
2652         // read and verify additional cell positions
2653         for( sal_uInt32 nIndex = 2; bValid && (nIndex < nCount); ++nIndex )
2654         {
2655             aAddr1 = aAddr2;
2656             rStrm >> aAddr2;
2657             bValid = !rStrm.isEof() && lclIsValidNlrStack( aAddr1, aAddr2, orbIsRow );
2658         }
2659         // check that last imported position (aAddr2) is not at the end of the sheet
2660         bValid = bValid && (orbIsRow ? (aAddr2.mnCol < mnMaxApiCol) : (aAddr2.mnRow < mnMaxApiRow));
2661         // fill the NLR struct with the last imported position
2662         if( bValid )
2663         {
2664             orNlr.mnCol = aAddr2.mnCol;
2665             orNlr.mnRow = aAddr2.mnRow;
2666             orNlr.mbRel = bRel;
2667         }
2668     }
2669     // seek to end of additional data for this token
2670     rStrm.seek( nEndPos );
2671     swapStreamPosition( rStrm );
2672 
2673     return bValid;
2674 }
2675 
2676 // convert BIFF token and push API operand or operator ------------------------
2677 
2678 bool BiffFormulaParserImpl::pushBiffReference( const BinSingleRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
2679 {
2680     return (mnCurrRefId > 0) ?
2681         pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
2682         pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
2683 }
2684 
2685 bool BiffFormulaParserImpl::pushBiffReference( const BinComplexRef2d& rRef, bool bDeleted, bool bRelativeAsOffset )
2686 {
2687     return (mnCurrRefId > 0) ?
2688         pushReferenceOperand( getExternalLinks().getSheetRange( mnCurrRefId, 0, 0 ), rRef, bDeleted, bRelativeAsOffset ) :
2689         pushReferenceOperand( rRef, bDeleted, bRelativeAsOffset );
2690 }
2691 
2692 bool BiffFormulaParserImpl::pushBiffNlrAddr( const BiffNlr& rNlr, bool bRow )
2693 {
2694     BinSingleRef2d aRef;
2695     aRef.mnCol = rNlr.mnCol;
2696     aRef.mnRow = rNlr.mnRow;
2697     aRef.mbColRel = !bRow;
2698     aRef.mbRowRel = bRow;
2699     return pushNlrOperand( aRef );
2700 }
2701 
2702 bool BiffFormulaParserImpl::pushBiffNlrRange( const BiffNlr& rNlr, const BinRange& rRange )
2703 {
2704     bool bRow = rNlr.mnRow == rRange.maFirst.mnRow;
2705     return lclIsValidNlrRange( rNlr, rRange, bRow ) ?
2706         pushBiffNlrAddr( rNlr, bRow ) : pushBiffErrorOperand( BIFF_ERR_REF );
2707 }
2708 
2709 bool BiffFormulaParserImpl::pushBiffNlrSAddr( const BiffNlr& rNlr, bool bRow )
2710 {
2711     BinRange aRange;
2712     aRange.maFirst.mnCol = rNlr.mnCol + (bRow ? 1 : 0);
2713     aRange.maFirst.mnRow = rNlr.mnRow + (bRow ? 0 : 1);
2714     aRange.maLast.mnCol = bRow ? mnMaxApiCol : rNlr.mnCol;
2715     aRange.maLast.mnRow = bRow ? rNlr.mnRow : mnMaxApiRow;
2716     return pushBiffNlrSRange( rNlr, aRange, bRow );
2717 }
2718 
2719 bool BiffFormulaParserImpl::pushBiffNlrSRange( const BiffNlr& rNlr, const BinRange& rRange, bool bRow )
2720 {
2721     if( lclIsValidNlrRange( rNlr, rRange, bRow ) )
2722     {
2723         BinComplexRef2d aRef;
2724         aRef.maRef1.mnCol = rRange.maFirst.mnCol;
2725         aRef.maRef1.mnRow = rRange.maFirst.mnRow;
2726         aRef.maRef2.mnCol = rRange.maLast.mnCol;
2727         aRef.maRef2.mnRow = rRange.maLast.mnRow;
2728         aRef.maRef1.mbColRel = aRef.maRef2.mbColRel = !bRow && rNlr.mbRel;
2729         aRef.maRef1.mbRowRel = aRef.maRef2.mbRowRel = bRow && rNlr.mbRel;
2730         return pushReferenceOperand( aRef, false, false );
2731     }
2732     return pushBiffErrorOperand( BIFF_ERR_REF );
2733 }
2734 
2735 bool BiffFormulaParserImpl::pushBiffName( sal_uInt16 nNameId )
2736 {
2737     // one-based in BIFF formulas
2738     return pushDefinedNameOperand( getDefinedNames().getByIndex( static_cast< sal_Int32 >( nNameId ) - 1 ) );
2739 }
2740 
2741 bool BiffFormulaParserImpl::pushBiffExtName( sal_Int32 nRefId, sal_uInt16 nNameId )
2742 {
2743     if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
2744     {
2745         if( pExtLink->getLinkType() == LINKTYPE_SELF )
2746             return pushBiffName( nNameId );
2747         // external name indexes are one-based in BIFF
2748         ExternalNameRef xExtName = pExtLink->getNameByIndex( static_cast< sal_Int32 >( nNameId ) - 1 );
2749         return pushExternalNameOperand( xExtName, *pExtLink );
2750     }
2751     return pushBiffErrorOperand( BIFF_ERR_NAME );
2752 }
2753 
2754 bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId )
2755 {
2756     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( nFuncId ) )
2757         if( pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount )
2758             return pushFunctionOperator( *pFuncInfo, pFuncInfo->mnMinParamCount );
2759     return pushFunctionOperator( OPCODE_NONAME, 0 );
2760 }
2761 
2762 bool BiffFormulaParserImpl::pushBiffFunction( sal_uInt16 nFuncId, sal_uInt8 nParamCount )
2763 {
2764     if( getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD ) )
2765         nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
2766     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( nFuncId ) )
2767         return pushFunctionOperator( *pFuncInfo, nParamCount );
2768     return pushFunctionOperator( OPCODE_NONAME, nParamCount );
2769 }
2770 
2771 // ============================================================================
2772 
2773 namespace {
2774 
2775 /** Extracts the reference identifier and the remaining data from a formula in
2776     the format '[RefID]Remaining'. */
2777 bool lclExtractRefId( sal_Int32& rnRefId, OUString& rRemainder, const OUString& rFormulaString )
2778 {
2779     if( (rFormulaString.getLength() >= 4) && (rFormulaString[ 0 ] == '[') )
2780     {
2781         sal_Int32 nBracketClose = rFormulaString.indexOf( ']', 1 );
2782         if( nBracketClose >= 2 )
2783         {
2784             rnRefId = rFormulaString.copy( 1, nBracketClose - 1 ).toInt32();
2785             rRemainder = rFormulaString.copy( nBracketClose + 1 );
2786             return rRemainder.getLength() > 0;
2787         }
2788     }
2789     return false;
2790 }
2791 
2792 }
2793 
2794 // ----------------------------------------------------------------------------
2795 
2796 FormulaParser::FormulaParser( const WorkbookHelper& rHelper ) :
2797     FormulaProcessorBase( rHelper )
2798 {
2799     switch( getFilterType() )
2800     {
2801         case FILTER_OOXML:  mxImpl.reset( new OoxFormulaParserImpl( *this ) );  break;
2802         case FILTER_BIFF:   mxImpl.reset( new BiffFormulaParserImpl( *this ) ); break;
2803         case FILTER_UNKNOWN: break;
2804     }
2805 }
2806 
2807 FormulaParser::~FormulaParser()
2808 {
2809 }
2810 
2811 ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, const OUString& rFormulaString ) const
2812 {
2813     return mxImpl->importOoxFormula( rBaseAddress, rFormulaString );
2814 }
2815 
2816 ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, FormulaType eType, SequenceInputStream& rStrm ) const
2817 {
2818     return mxImpl->importBiff12Formula( rBaseAddress, eType, rStrm );
2819 }
2820 
2821 ApiTokenSequence FormulaParser::importFormula( const CellAddress& rBaseAddress, FormulaType eType, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
2822 {
2823     return mxImpl->importBiffFormula( rBaseAddress, eType, rStrm, pnFmlaSize );
2824 }
2825 
2826 ApiTokenSequence FormulaParser::convertBoolToFormula( bool bValue ) const
2827 {
2828     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( bValue ? BIFF_FUNC_TRUE : BIFF_FUNC_FALSE ) )
2829     {
2830         ApiTokenSequence aTokens( 3 );
2831         aTokens[ 0 ].OpCode = pFuncInfo->mnApiOpCode;
2832         aTokens[ 1 ].OpCode = OPCODE_OPEN;
2833         aTokens[ 2 ].OpCode = OPCODE_CLOSE;
2834         return aTokens;
2835     }
2836     return ApiTokenSequence();
2837 }
2838 
2839 ApiTokenSequence FormulaParser::convertErrorToFormula( sal_uInt8 nErrorCode ) const
2840 {
2841     ApiTokenSequence aTokens( 3 );
2842     // HACK: enclose all error codes into an 1x1 matrix
2843     aTokens[ 0 ].OpCode = OPCODE_ARRAY_OPEN;
2844     aTokens[ 1 ].OpCode = OPCODE_PUSH;
2845     aTokens[ 1 ].Data <<= BiffHelper::calcDoubleFromError( nErrorCode );
2846     aTokens[ 2 ].OpCode = OPCODE_ARRAY_CLOSE;
2847     return aTokens;
2848 }
2849 
2850 ApiTokenSequence FormulaParser::convertNameToFormula( sal_Int32 nTokenIndex ) const
2851 {
2852     if( nTokenIndex < 0 )
2853         return convertErrorToFormula( BIFF_ERR_REF );
2854 
2855     ApiTokenSequence aTokens( 1 );
2856     aTokens[ 0 ].OpCode = OPCODE_NAME;
2857     aTokens[ 0 ].Data <<= nTokenIndex;
2858     return aTokens;
2859 }
2860 
2861 ApiTokenSequence FormulaParser::convertNumberToHyperlink( const OUString& rUrl, double fValue ) const
2862 {
2863     OSL_ENSURE( rUrl.getLength() > 0, "FormulaParser::convertNumberToHyperlink - missing URL" );
2864     if( const FunctionInfo* pFuncInfo = getFuncInfoFromBiffFuncId( BIFF_FUNC_HYPERLINK ) )
2865     {
2866         ApiTokenSequence aTokens( 6 );
2867         aTokens[ 0 ].OpCode = pFuncInfo->mnApiOpCode;
2868         aTokens[ 1 ].OpCode = OPCODE_OPEN;
2869         aTokens[ 2 ].OpCode = OPCODE_PUSH;
2870         aTokens[ 2 ].Data <<= rUrl;
2871         aTokens[ 3 ].OpCode = OPCODE_SEP;
2872         aTokens[ 4 ].OpCode = OPCODE_PUSH;
2873         aTokens[ 4 ].Data <<= fValue;
2874         aTokens[ 5 ].OpCode = OPCODE_CLOSE;
2875         return aTokens;
2876     }
2877     return ApiTokenSequence();
2878 }
2879 
2880 OUString FormulaParser::importOleTargetLink( const OUString& rFormulaString )
2881 {
2882     sal_Int32 nRefId = -1;
2883     OUString aRemainder;
2884     if( lclExtractRefId( nRefId, aRemainder, rFormulaString ) && (aRemainder.getLength() >= 3) &&
2885             (aRemainder[ 0 ] == '!') && (aRemainder[ 1 ] == '\'') && (aRemainder[ aRemainder.getLength() - 1 ] == '\'') )
2886         return mxImpl->resolveOleTarget( nRefId, false );
2887     return OUString();
2888 }
2889 
2890 OUString FormulaParser::importOleTargetLink( SequenceInputStream& rStrm )
2891 {
2892     OUString aTargetLink;
2893     sal_Int32 nFmlaSize = rStrm.readInt32();
2894     sal_Int64 nFmlaEndPos = rStrm.tell() + ::std::max< sal_Int32 >( nFmlaSize, 0 );
2895     if( (nFmlaSize == 7) && (rStrm.getRemaining() >= 7) )
2896     {
2897         sal_uInt8 nToken;
2898         sal_Int16 nRefId;
2899         sal_Int32 nNameId;
2900         rStrm >> nToken >> nRefId >> nNameId;
2901         if( nToken == (BIFF_TOKCLASS_VAL|BIFF_TOKID_NAMEX) )
2902             aTargetLink = mxImpl->resolveOleTarget( nRefId, true );
2903     }
2904     rStrm.seek( nFmlaEndPos );
2905     return aTargetLink;
2906 }
2907 
2908 OUString FormulaParser::importOleTargetLink( BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) const
2909 {
2910     OUString aTargetLink;
2911     sal_uInt16 nFmlaSize = lclReadFmlaSize( rStrm, getBiff(), pnFmlaSize );
2912     rStrm.skip( nFmlaSize );
2913     return aTargetLink;
2914 }
2915 
2916 OUString FormulaParser::importMacroName( const OUString& rFormulaString )
2917 {
2918     /*  Valid macros are either sheet macros or VBA macros. OOXML and all BIFF
2919         documents store defined names for sheet macros, but OOXML documents do
2920         not store any defined name for VBA macros (while BIFF documents do).
2921         Sheet macros may be defined locally to a sheet, or globally to the
2922         document. As a result, all of the following macro specifiers are valid:
2923 
2924         1) Macros located in the own document:
2925             [0]!MySheetMacro    (global sheet macro 'MySheetMacro')
2926             Macro1!MyMacro      (sheet-local sheet macro 'MyMacro')
2927             [0]!MyVBAProc       (VBA macro 'MyVBAProc')
2928             [0]!Mod1.MyVBAProc  (VBA macro 'MyVBAProc' from code module 'Mod1')
2929 
2930         2) Macros from an external document:
2931             [2]!MySheetMacro    (global external sheet macro 'MySheetMacro')
2932             [2]Macro1!MyMacro   (sheet-local external sheet macro 'MyMacro')
2933             [2]!MyVBAProc       (external VBA macro 'MyVBAProc')
2934             [2]!Mod1.MyVBAProc  (external VBA macro from code module 'Mod1')
2935 
2936         This implementation is only interested in VBA macros from the own
2937         document, ignoring the valid syntax 'Macro1!MyMacro' for sheet-local
2938         sheet macros.
2939      */
2940     sal_Int32 nRefId = -1;
2941     OUString aRemainder;
2942     if( lclExtractRefId( nRefId, aRemainder, rFormulaString ) && (aRemainder.getLength() > 1) && (aRemainder[ 0 ] == '!') )
2943     {
2944         /*  In BIFF12 documents, the reference identifier is always the
2945             one-based index of the external link as it is in OOXML documents
2946             (it is not an index into the list of reference sheets as used in
2947             cell formulas). Index 0 is an implicit placeholder for the own
2948             document. In BIFF12 documents, the reference to the own document is
2949             stored explicitly, mostly at the top of the list, so index 1 may
2950             resolve to the own document too.
2951             Passing 'false' to getExternalLink() specifies to ignore the
2952             reference sheets list (if existing) and to access the list of
2953             external links directly. */
2954         const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId, false ).get();
2955         OSL_ENSURE( pExtLink, "FormulaParser::importMacroName - missing link" );
2956         // do not accept macros in external documents (not supported)
2957         if( pExtLink && (pExtLink->getLinkType() == LINKTYPE_SELF) )
2958         {
2959             // ignore sheet macros (defined name for VBA macros may not exist, see above)
2960             OUString aMacroName = aRemainder.copy( 1 );
2961             const DefinedName* pDefName = getDefinedNames().getByModelName( aMacroName ).get();
2962             if( !pDefName || pDefName->isVBName() )
2963                 return aMacroName;
2964         }
2965     }
2966     return OUString();
2967 }
2968 
2969 // ============================================================================
2970 
2971 } // namespace xls
2972 } // namespace oox
2973