1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21 #include <algorithm>
22
23 #include <string.h>
24 #include <limits.h>
25 #include <osl/diagnose.h>
26 #include <sal/log.hxx>
27
28 #include <com/sun/star/sheet/FormulaToken.hpp>
29 #include <formula/errorcodes.hxx>
30 #include <formula/token.hxx>
31 #include <formula/tokenarray.hxx>
32 #include <formula/FormulaCompiler.hxx>
33 #include <formula/compiler.hxx>
34 #include <svl/sharedstringpool.hxx>
35 #include <memory>
36
37 namespace formula
38 {
39 using namespace com::sun::star;
40
41
42 // --- helpers --------------------------------------------------------------
43
lcl_IsReference(OpCode eOp,StackVar eType)44 static bool lcl_IsReference( OpCode eOp, StackVar eType )
45 {
46 return
47 (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef))
48 || (eOp == ocColRowNameAuto && eType == svDoubleRef)
49 || (eOp == ocColRowName && eType == svSingleRef)
50 || (eOp == ocMatRef && eType == svSingleRef)
51 ;
52 }
53
54 // --- class FormulaToken --------------------------------------------------------
55
FormulaToken(StackVar eTypeP,OpCode e)56 FormulaToken::FormulaToken( StackVar eTypeP, OpCode e ) :
57 eOp(e), eType( eTypeP ), mnRefCnt(0)
58 {
59 }
60
FormulaToken(const FormulaToken & r)61 FormulaToken::FormulaToken( const FormulaToken& r ) :
62 eOp(r.eOp), eType( r.eType ), mnRefCnt(0)
63 {
64 }
65
~FormulaToken()66 FormulaToken::~FormulaToken()
67 {
68 }
69
IsFunction() const70 bool FormulaToken::IsFunction() const
71 {
72 return (eOp != ocPush && eOp != ocBad && eOp != ocColRowName &&
73 eOp != ocColRowNameAuto && eOp != ocName && eOp != ocDBArea &&
74 eOp != ocTableRef &&
75 (GetByte() != 0 // x parameters
76 || (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR) // no parameter
77 || FormulaCompiler::IsOpCodeJumpCommand( eOp ) // @ jump commands
78 || (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR) // one parameter
79 || (SC_OPCODE_START_2_PAR <= eOp && eOp < SC_OPCODE_STOP_2_PAR) // x parameters (cByte==0 in
80 // FuncAutoPilot)
81 || eOp == ocMacro || eOp == ocExternal // macros, AddIns
82 || eOp == ocAnd || eOp == ocOr // former binary, now x parameters
83 || (eOp >= ocInternalBegin && eOp <= ocInternalEnd) // internal
84 ));
85 }
86
87
GetParamCount() const88 sal_uInt8 FormulaToken::GetParamCount() const
89 {
90 if ( eOp < SC_OPCODE_STOP_DIV && eOp != ocExternal && eOp != ocMacro &&
91 !FormulaCompiler::IsOpCodeJumpCommand( eOp ) &&
92 eOp != ocPercentSign )
93 return 0; // parameters and specials
94 // ocIf... jump commands not for FAP, have cByte then
95 //2do: bool parameter whether FAP or not?
96 else if ( GetByte() )
97 return GetByte(); // all functions, also ocExternal and ocMacro
98 else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP)
99 return 2; // binary
100 else if ((SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
101 || eOp == ocPercentSign)
102 return 1; // unary
103 else if (SC_OPCODE_START_NO_PAR <= eOp && eOp < SC_OPCODE_STOP_NO_PAR)
104 return 0; // no parameter
105 else if (SC_OPCODE_START_1_PAR <= eOp && eOp < SC_OPCODE_STOP_1_PAR)
106 return 1; // one parameter
107 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
108 return 1; // only the condition counts as parameter
109 else
110 return 0; // all the rest, no Parameter, or
111 // if so then it should be in cByte
112 }
113
IsExternalRef() const114 bool FormulaToken::IsExternalRef() const
115 {
116 bool bRet = false;
117 switch (eType)
118 {
119 case svExternalSingleRef:
120 case svExternalDoubleRef:
121 case svExternalName:
122 bRet = true;
123 break;
124 default:
125 bRet = false;
126 break;
127 }
128 return bRet;
129 }
130
IsRef() const131 bool FormulaToken::IsRef() const
132 {
133 switch (eType)
134 {
135 case svSingleRef:
136 case svDoubleRef:
137 case svExternalSingleRef:
138 case svExternalDoubleRef:
139 return true;
140 default:
141 if (eOp == ocTableRef)
142 return true;
143 }
144
145 return false;
146 }
147
IsInForceArray() const148 bool FormulaToken::IsInForceArray() const
149 {
150 ParamClass eParam = GetInForceArray();
151 return eParam == ParamClass::ForceArray || eParam == ParamClass::ReferenceOrForceArray
152 || eParam == ParamClass::ReferenceOrRefArray || eParam == ParamClass::ForceArrayReturn;
153 }
154
operator ==(const FormulaToken & rToken) const155 bool FormulaToken::operator==( const FormulaToken& rToken ) const
156 {
157 // don't compare reference count!
158 return eType == rToken.eType && GetOpCode() == rToken.GetOpCode();
159 }
160
161
162 // --- virtual dummy methods -------------------------------------------------
163
GetByte() const164 sal_uInt8 FormulaToken::GetByte() const
165 {
166 // ok to be called for any derived class
167 return 0;
168 }
169
SetByte(sal_uInt8)170 void FormulaToken::SetByte( sal_uInt8 )
171 {
172 assert( !"virtual dummy called" );
173 }
174
GetInForceArray() const175 ParamClass FormulaToken::GetInForceArray() const
176 {
177 // ok to be called for any derived class
178 return ParamClass::Unknown;
179 }
180
SetInForceArray(ParamClass)181 void FormulaToken::SetInForceArray( ParamClass )
182 {
183 assert( !"virtual dummy called" );
184 }
185
GetDouble() const186 double FormulaToken::GetDouble() const
187 {
188 // This Get is worth an assert.
189 assert( !"virtual dummy called" );
190 return 0.0;
191 }
192
GetDoubleAsReference()193 double & FormulaToken::GetDoubleAsReference()
194 {
195 // This Get is worth an assert.
196 assert( !"virtual dummy called" );
197 static double fVal = 0.0;
198 return fVal;
199 }
200
GetDoubleType() const201 sal_Int16 FormulaToken::GetDoubleType() const
202 {
203 SAL_WARN( "formula.core", "FormulaToken::GetDoubleType: virtual dummy called" );
204 return 0;
205 }
206
SetDoubleType(sal_Int16)207 void FormulaToken::SetDoubleType( sal_Int16 )
208 {
209 assert( !"virtual dummy called" );
210 }
211
212 const svl::SharedString INVALID_STRING;
213
GetString() const214 const svl::SharedString & FormulaToken::GetString() const
215 {
216 SAL_WARN( "formula.core", "FormulaToken::GetString: virtual dummy called" );
217 return INVALID_STRING; // invalid string
218 }
219
SetString(const svl::SharedString &)220 void FormulaToken::SetString( const svl::SharedString& )
221 {
222 assert( !"virtual dummy called" );
223 }
224
GetIndex() const225 sal_uInt16 FormulaToken::GetIndex() const
226 {
227 SAL_WARN( "formula.core", "FormulaToken::GetIndex: virtual dummy called" );
228 return 0;
229 }
230
SetIndex(sal_uInt16)231 void FormulaToken::SetIndex( sal_uInt16 )
232 {
233 assert( !"virtual dummy called" );
234 }
235
GetSheet() const236 sal_Int16 FormulaToken::GetSheet() const
237 {
238 SAL_WARN( "formula.core", "FormulaToken::GetSheet: virtual dummy called" );
239 return -1;
240 }
241
SetSheet(sal_Int16)242 void FormulaToken::SetSheet( sal_Int16 )
243 {
244 assert( !"virtual dummy called" );
245 }
246
GetJump() const247 short* FormulaToken::GetJump() const
248 {
249 SAL_WARN( "formula.core", "FormulaToken::GetJump: virtual dummy called" );
250 return nullptr;
251 }
252
253
GetExternal() const254 const OUString& FormulaToken::GetExternal() const
255 {
256 SAL_WARN( "formula.core", "FormulaToken::GetExternal: virtual dummy called" );
257 static OUString aDummyString;
258 return aDummyString;
259 }
260
GetFAPOrigToken() const261 FormulaToken* FormulaToken::GetFAPOrigToken() const
262 {
263 SAL_WARN( "formula.core", "FormulaToken::GetFAPOrigToken: virtual dummy called" );
264 return nullptr;
265 }
266
GetError() const267 FormulaError FormulaToken::GetError() const
268 {
269 SAL_WARN( "formula.core", "FormulaToken::GetError: virtual dummy called" );
270 return FormulaError::NONE;
271 }
272
SetError(FormulaError)273 void FormulaToken::SetError( FormulaError )
274 {
275 assert( !"virtual dummy called" );
276 }
277
GetSingleRef() const278 const ScSingleRefData* FormulaToken::GetSingleRef() const
279 {
280 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
281 return nullptr;
282 }
283
GetSingleRef()284 ScSingleRefData* FormulaToken::GetSingleRef()
285 {
286 OSL_FAIL( "FormulaToken::GetSingleRef: virtual dummy called" );
287 return nullptr;
288 }
289
GetDoubleRef() const290 const ScComplexRefData* FormulaToken::GetDoubleRef() const
291 {
292 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
293 return nullptr;
294 }
295
GetDoubleRef()296 ScComplexRefData* FormulaToken::GetDoubleRef()
297 {
298 OSL_FAIL( "FormulaToken::GetDoubleRef: virtual dummy called" );
299 return nullptr;
300 }
301
GetSingleRef2() const302 const ScSingleRefData* FormulaToken::GetSingleRef2() const
303 {
304 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
305 return nullptr;
306 }
307
GetSingleRef2()308 ScSingleRefData* FormulaToken::GetSingleRef2()
309 {
310 OSL_FAIL( "FormulaToken::GetSingleRef2: virtual dummy called" );
311 return nullptr;
312 }
313
GetMatrix() const314 const ScMatrix* FormulaToken::GetMatrix() const
315 {
316 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
317 return nullptr;
318 }
319
GetMatrix()320 ScMatrix* FormulaToken::GetMatrix()
321 {
322 OSL_FAIL( "FormulaToken::GetMatrix: virtual dummy called" );
323 return nullptr;
324 }
325
GetJumpMatrix() const326 ScJumpMatrix* FormulaToken::GetJumpMatrix() const
327 {
328 OSL_FAIL( "FormulaToken::GetJumpMatrix: virtual dummy called" );
329 return nullptr;
330 }
GetRefList() const331 const std::vector<ScComplexRefData>* FormulaToken::GetRefList() const
332 {
333 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
334 return nullptr;
335 }
336
GetRefList()337 std::vector<ScComplexRefData>* FormulaToken::GetRefList()
338 {
339 OSL_FAIL( "FormulaToken::GetRefList: virtual dummy called" );
340 return nullptr;
341 }
342
TextEqual(const FormulaToken & rToken) const343 bool FormulaToken::TextEqual( const FormulaToken& rToken ) const
344 {
345 return *this == rToken;
346 }
347
348 // real implementations of virtual functions
349
350
GetByte() const351 sal_uInt8 FormulaByteToken::GetByte() const { return nByte; }
SetByte(sal_uInt8 n)352 void FormulaByteToken::SetByte( sal_uInt8 n ) { nByte = n; }
GetInForceArray() const353 ParamClass FormulaByteToken::GetInForceArray() const { return eInForceArray; }
SetInForceArray(ParamClass c)354 void FormulaByteToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
operator ==(const FormulaToken & r) const355 bool FormulaByteToken::operator==( const FormulaToken& r ) const
356 {
357 return FormulaToken::operator==( r ) && nByte == r.GetByte() &&
358 eInForceArray == r.GetInForceArray();
359 }
360
361
GetFAPOrigToken() const362 FormulaToken* FormulaFAPToken::GetFAPOrigToken() const { return pOrigToken.get(); }
operator ==(const FormulaToken & r) const363 bool FormulaFAPToken::operator==( const FormulaToken& r ) const
364 {
365 return FormulaByteToken::operator==( r ) && pOrigToken == r.GetFAPOrigToken();
366 }
367
368
GetJump() const369 short* FormulaJumpToken::GetJump() const { return pJump.get(); }
GetInForceArray() const370 ParamClass FormulaJumpToken::GetInForceArray() const { return eInForceArray; }
SetInForceArray(ParamClass c)371 void FormulaJumpToken::SetInForceArray( ParamClass c ) { eInForceArray = c; }
operator ==(const FormulaToken & r) const372 bool FormulaJumpToken::operator==( const FormulaToken& r ) const
373 {
374 return FormulaToken::operator==( r ) && pJump[0] == r.GetJump()[0] &&
375 memcmp( pJump.get()+1, r.GetJump()+1, pJump[0] * sizeof(short) ) == 0 &&
376 eInForceArray == r.GetInForceArray();
377 }
~FormulaJumpToken()378 FormulaJumpToken::~FormulaJumpToken()
379 {
380 }
381
382
AddFormulaToken(const sheet::FormulaToken & rToken,svl::SharedStringPool & rSPool,ExternalReferenceHelper *)383 bool FormulaTokenArray::AddFormulaToken(
384 const sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, ExternalReferenceHelper* /*pExtRef*/)
385 {
386 bool bError = false;
387 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); //! assuming equal values for the moment
388
389 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
390 switch ( eClass )
391 {
392 case uno::TypeClass_VOID:
393 // empty data -> use AddOpCode (does some special cases)
394 AddOpCode( eOpCode );
395 break;
396 case uno::TypeClass_DOUBLE:
397 // double is only used for "push"
398 if ( eOpCode == ocPush )
399 AddDouble( rToken.Data.get<double>() );
400 else
401 bError = true;
402 break;
403 case uno::TypeClass_LONG:
404 {
405 // long is svIndex, used for name / database area, or "byte" for spaces
406 sal_Int32 nValue = rToken.Data.get<sal_Int32>();
407 if ( eOpCode == ocDBArea )
408 Add( new formula::FormulaIndexToken( eOpCode, static_cast<sal_uInt16>(nValue) ) );
409 else if ( eOpCode == ocTableRef )
410 bError = true; /* TODO: implementation */
411 else if ( eOpCode == ocSpaces )
412 Add( new formula::FormulaByteToken( ocSpaces, static_cast<sal_uInt8>(nValue) ) );
413 else
414 bError = true;
415 }
416 break;
417 case uno::TypeClass_STRING:
418 {
419 OUString aStrVal( rToken.Data.get<OUString>() );
420 if ( eOpCode == ocPush )
421 AddString(rSPool.intern(aStrVal));
422 else if ( eOpCode == ocBad )
423 AddBad( aStrVal );
424 else if ( eOpCode == ocStringXML )
425 AddStringXML( aStrVal );
426 else if ( eOpCode == ocExternal || eOpCode == ocMacro )
427 Add( new formula::FormulaExternalToken( eOpCode, aStrVal ) );
428 else
429 bError = true; // unexpected string: don't know what to do with it
430 }
431 break;
432 default:
433 bError = true;
434 } // switch ( eClass )
435 return bError;
436 }
437
Fill(const uno::Sequence<sheet::FormulaToken> & rSequence,svl::SharedStringPool & rSPool,ExternalReferenceHelper * pExtRef)438 bool FormulaTokenArray::Fill(
439 const uno::Sequence<sheet::FormulaToken>& rSequence,
440 svl::SharedStringPool& rSPool, ExternalReferenceHelper* pExtRef )
441 {
442 bool bError = false;
443 const sal_Int32 nCount = rSequence.getLength();
444 for (sal_Int32 nPos=0; nPos<nCount; nPos++)
445 {
446 bool bOneError = AddFormulaToken(rSequence[nPos], rSPool, pExtRef);
447 if (bOneError)
448 {
449 AddOpCode( ocErrName); // add something that indicates an error
450 bError = true;
451 }
452 }
453 return bError;
454 }
455
DelRPN()456 void FormulaTokenArray::DelRPN()
457 {
458 if( nRPN )
459 {
460 FormulaToken** p = pRPN;
461 for( sal_uInt16 i = 0; i < nRPN; i++ )
462 {
463 (*p++)->DecRef();
464 }
465 delete [] pRPN;
466 }
467 pRPN = nullptr;
468 nRPN = 0;
469 }
470
FirstToken() const471 FormulaToken* FormulaTokenArray::FirstToken() const
472 {
473 if (!pCode || nLen == 0)
474 return nullptr;
475 return pCode[0];
476 }
477
PeekPrev(sal_uInt16 & nIdx) const478 FormulaToken* FormulaTokenArray::PeekPrev( sal_uInt16 & nIdx ) const
479 {
480 if (0 < nIdx && nIdx <= nLen)
481 return pCode[--nIdx];
482 return nullptr;
483 }
484
FirstRPNToken() const485 FormulaToken* FormulaTokenArray::FirstRPNToken() const
486 {
487 if (!pRPN || nRPN == 0)
488 return nullptr;
489 return pRPN[0];
490 }
491
HasReferences() const492 bool FormulaTokenArray::HasReferences() const
493 {
494 for (auto i: Tokens())
495 {
496 if (i->IsRef())
497 return true;
498 }
499
500 for (auto i: RPNTokens())
501 {
502 if (i->IsRef())
503 return true;
504 }
505
506 return false;
507 }
508
HasExternalRef() const509 bool FormulaTokenArray::HasExternalRef() const
510 {
511 for (auto i: Tokens())
512 {
513 if (i->IsExternalRef())
514 return true;
515 }
516 return false;
517 }
518
HasOpCode(OpCode eOp) const519 bool FormulaTokenArray::HasOpCode( OpCode eOp ) const
520 {
521 for (auto i: Tokens())
522 {
523 if (i->GetOpCode() == eOp)
524 return true;
525 }
526 return false;
527 }
528
HasOpCodeRPN(OpCode eOp) const529 bool FormulaTokenArray::HasOpCodeRPN( OpCode eOp ) const
530 {
531 for (auto i: RPNTokens())
532 {
533 if (i->GetOpCode() == eOp)
534 return true;
535 }
536 return false;
537 }
538
HasNameOrColRowName() const539 bool FormulaTokenArray::HasNameOrColRowName() const
540 {
541 for (auto i: Tokens())
542 {
543 if (i->GetType() == svIndex || i->GetOpCode() == ocColRowName )
544 return true;
545 }
546 return false;
547 }
548
HasOpCodes(const unordered_opcode_set & rOpCodes) const549 bool FormulaTokenArray::HasOpCodes(const unordered_opcode_set& rOpCodes) const
550 {
551 for (auto i: Tokens())
552 {
553 if (rOpCodes.count(i->GetOpCode()) > 0)
554 return true;
555 }
556
557 return false;
558 }
559
FormulaTokenArray()560 FormulaTokenArray::FormulaTokenArray() :
561 pRPN(nullptr),
562 nLen(0),
563 nRPN(0),
564 nError(FormulaError::NONE),
565 nMode(ScRecalcMode::NORMAL),
566 bHyperLink(false),
567 mbFromRangeName(false),
568 mbShareable(true),
569 mbFinalized(false)
570 {
571 }
572
FormulaTokenArray(const FormulaTokenArray & rArr)573 FormulaTokenArray::FormulaTokenArray( const FormulaTokenArray& rArr )
574 {
575 Assign( rArr );
576 }
577
~FormulaTokenArray()578 FormulaTokenArray::~FormulaTokenArray()
579 {
580 FormulaTokenArray::Clear();
581 }
582
Finalize()583 void FormulaTokenArray::Finalize()
584 {
585 if( nLen && !mbFinalized )
586 {
587 // Add() overallocates, so reallocate to the minimum needed size.
588 std::unique_ptr<FormulaToken*[]> newCode(new FormulaToken*[ nLen ]);
589 std::copy(&pCode[0], &pCode[nLen], newCode.get());
590 pCode = std::move( newCode );
591 mbFinalized = true;
592 }
593 }
594
Assign(const FormulaTokenArray & r)595 void FormulaTokenArray::Assign( const FormulaTokenArray& r )
596 {
597 nLen = r.nLen;
598 nRPN = r.nRPN;
599 nError = r.nError;
600 nMode = r.nMode;
601 bHyperLink = r.bHyperLink;
602 mbFromRangeName = r.mbFromRangeName;
603 mbShareable = r.mbShareable;
604 mbFinalized = r.mbFinalized;
605 pCode = nullptr;
606 pRPN = nullptr;
607 FormulaToken** pp;
608 if( nLen )
609 {
610 pCode.reset(new FormulaToken*[ nLen ]);
611 pp = pCode.get();
612 memcpy( pp, r.pCode.get(), nLen * sizeof( FormulaToken* ) );
613 for( sal_uInt16 i = 0; i < nLen; i++ )
614 (*pp++)->IncRef();
615 mbFinalized = true;
616 }
617 if( nRPN )
618 {
619 pp = pRPN = new FormulaToken*[ nRPN ];
620 memcpy( pp, r.pRPN, nRPN * sizeof( FormulaToken* ) );
621 for( sal_uInt16 i = 0; i < nRPN; i++ )
622 (*pp++)->IncRef();
623 }
624 }
625
626 /// Optimisation for efficiently creating StringXML placeholders
Assign(sal_uInt16 nCode,FormulaToken ** pTokens)627 void FormulaTokenArray::Assign( sal_uInt16 nCode, FormulaToken **pTokens )
628 {
629 assert( nLen == 0 );
630 assert( pCode == nullptr );
631
632 nLen = nCode;
633 pCode.reset(new FormulaToken*[ nLen ]);
634 mbFinalized = true;
635
636 for( sal_uInt16 i = 0; i < nLen; i++ )
637 {
638 FormulaToken *t = pTokens[ i ];
639 assert( t->GetOpCode() == ocStringXML );
640 pCode[ i ] = t;
641 t->IncRef();
642 }
643 }
644
operator =(const FormulaTokenArray & rArr)645 FormulaTokenArray& FormulaTokenArray::operator=( const FormulaTokenArray& rArr )
646 {
647 if(this == &rArr)
648 return *this;
649
650 Clear();
651 Assign( rArr );
652 return *this;
653 }
654
Clear()655 void FormulaTokenArray::Clear()
656 {
657 if( nRPN ) DelRPN();
658 if( pCode )
659 {
660 FormulaToken** p = pCode.get();
661 for( sal_uInt16 i = 0; i < nLen; i++ )
662 {
663 (*p++)->DecRef();
664 }
665 pCode.reset();
666 }
667 pRPN = nullptr;
668 nError = FormulaError::NONE;
669 nLen = nRPN = 0;
670 bHyperLink = false;
671 mbFromRangeName = false;
672 mbShareable = true;
673 mbFinalized = false;
674 ClearRecalcMode();
675 }
676
CheckToken(const FormulaToken &)677 void FormulaTokenArray::CheckToken( const FormulaToken& /*r*/ )
678 {
679 // Do nothing.
680 }
681
CheckAllRPNTokens()682 void FormulaTokenArray::CheckAllRPNTokens()
683 {
684 if( nRPN )
685 {
686 FormulaToken** p = pRPN;
687 for( sal_uInt16 i = 0; i < nRPN; i++ )
688 {
689 CheckToken( *p[ i ] );
690 }
691 }
692 }
693
AddToken(const FormulaToken & r)694 FormulaToken* FormulaTokenArray::AddToken( const FormulaToken& r )
695 {
696 return Add( r.Clone() );
697 }
698
MergeArray()699 FormulaToken* FormulaTokenArray::MergeArray( )
700 {
701 return nullptr;
702 }
703
ReplaceToken(sal_uInt16 nOffset,FormulaToken * t,FormulaTokenArray::ReplaceMode eMode)704 FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* t,
705 FormulaTokenArray::ReplaceMode eMode )
706 {
707 if (nOffset < nLen)
708 {
709 CheckToken(*t);
710 t->IncRef();
711 FormulaToken* p = pCode[nOffset];
712 pCode[nOffset] = t;
713 if (eMode == CODE_AND_RPN && p->GetRef() > 1)
714 {
715 for (sal_uInt16 i=0; i < nRPN; ++i)
716 {
717 if (pRPN[i] == p)
718 {
719 t->IncRef();
720 pRPN[i] = t;
721 p->DecRef();
722 if (p->GetRef() == 1)
723 break; // for
724 }
725 }
726 }
727 p->DecRef(); // may be dead now
728 return t;
729 }
730 else
731 {
732 t->DeleteIfZeroRef();
733 return nullptr;
734 }
735 }
736
RemoveToken(sal_uInt16 nOffset,sal_uInt16 nCount)737 sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
738 {
739 if (nOffset < nLen)
740 {
741 SAL_WARN_IF( nOffset + nCount > nLen, "formula.core",
742 "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen);
743 const sal_uInt16 nStop = ::std::min( static_cast<sal_uInt16>(nOffset + nCount), nLen);
744 nCount = nStop - nOffset;
745 for (sal_uInt16 j = nOffset; j < nStop; ++j)
746 {
747 FormulaToken* p = pCode[j];
748 if (p->GetRef() > 1)
749 {
750 for (sal_uInt16 i=0; i < nRPN; ++i)
751 {
752 if (pRPN[i] == p)
753 {
754 // Shift remaining tokens in pRPN down.
755 for (sal_uInt16 x=i+1; x < nRPN; ++x)
756 {
757 pRPN[x-1] = pRPN[x];
758 }
759 --nRPN;
760
761 p->DecRef();
762 if (p->GetRef() == 1)
763 break; // for
764 }
765 }
766 }
767 p->DecRef(); // may be dead now
768 }
769
770 // Shift remaining tokens in pCode down.
771 for (sal_uInt16 x = nStop; x < nLen; ++x)
772 {
773 pCode[x-nCount] = pCode[x];
774 }
775 nLen -= nCount;
776
777 return nCount;
778 }
779 else
780 {
781 SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen);
782 return 0;
783 }
784 }
785
Add(FormulaToken * t)786 FormulaToken* FormulaTokenArray::Add( FormulaToken* t )
787 {
788 assert(!mbFinalized);
789 if (mbFinalized)
790 {
791 t->DeleteIfZeroRef();
792 return nullptr;
793 }
794
795 // Allocating an array of size FORMULA_MAXTOKENS is simple, but that results in relatively large
796 // allocations that malloc() implementations usually do not handle as efficiently as smaller
797 // sizes (not only in terms of memory usage but also speed). Since most token arrays are going
798 // to be small, start with a small array and resize only if needed. Eventually Finalize() will
799 // reallocate the memory to size exactly matching the requirements.
800 const size_t MAX_FAST_TOKENS = 32;
801 if( !pCode )
802 pCode.reset(new FormulaToken*[ MAX_FAST_TOKENS ]);
803 if( nLen == MAX_FAST_TOKENS )
804 {
805 FormulaToken** tmp = new FormulaToken*[ FORMULA_MAXTOKENS ];
806 std::copy(&pCode[0], &pCode[MAX_FAST_TOKENS], tmp);
807 pCode.reset(tmp);
808 }
809 if( nLen < FORMULA_MAXTOKENS - 1 )
810 {
811 CheckToken(*t);
812 pCode[ nLen++ ] = t;
813 t->IncRef();
814 if( t->GetOpCode() == ocArrayClose )
815 return MergeArray();
816 return t;
817 }
818 else
819 {
820 t->DeleteIfZeroRef();
821 if ( nLen == FORMULA_MAXTOKENS - 1 )
822 {
823 t = new FormulaByteToken( ocStop );
824 pCode[ nLen++ ] = t;
825 t->IncRef();
826 }
827 return nullptr;
828 }
829 }
830
AddString(const svl::SharedString & rStr)831 FormulaToken* FormulaTokenArray::AddString( const svl::SharedString& rStr )
832 {
833 return Add( new FormulaStringToken( rStr ) );
834 }
835
AddDouble(double fVal)836 FormulaToken* FormulaTokenArray::AddDouble( double fVal )
837 {
838 return Add( new FormulaDoubleToken( fVal ) );
839 }
840
AddExternal(const sal_Unicode * pStr)841 void FormulaTokenArray::AddExternal( const sal_Unicode* pStr )
842 {
843 AddExternal( OUString( pStr ) );
844 }
845
AddExternal(const OUString & rStr,OpCode eOp)846 FormulaToken* FormulaTokenArray::AddExternal( const OUString& rStr,
847 OpCode eOp /* = ocExternal */ )
848 {
849 return Add( new FormulaExternalToken( eOp, rStr ) );
850 }
851
AddBad(const OUString & rStr)852 FormulaToken* FormulaTokenArray::AddBad( const OUString& rStr )
853 {
854 return Add( new FormulaStringOpToken( ocBad, svl::SharedString( rStr ) ) ); // string not interned
855 }
856
AddStringXML(const OUString & rStr)857 FormulaToken* FormulaTokenArray::AddStringXML( const OUString& rStr )
858 {
859 return Add( new FormulaStringOpToken( ocStringXML, svl::SharedString( rStr ) ) ); // string not interned
860 }
861
862
AddRecalcMode(ScRecalcMode nBits)863 void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
864 {
865 const unsigned nExclusive = static_cast<sal_uInt8>(nBits & ScRecalcMode::EMask);
866 if (nExclusive)
867 {
868 unsigned nExBit;
869 if (nExclusive & (nExclusive - 1))
870 {
871 // More than one bit set, use highest priority.
872 for (nExBit = 1; (nExBit & static_cast<sal_uInt8>(ScRecalcMode::EMask)) != 0; nExBit <<= 1)
873 {
874 if (nExclusive & nExBit)
875 break;
876 }
877 }
878 else
879 {
880 // Only one bit is set.
881 nExBit = nExclusive;
882 }
883 // Set exclusive bit if priority is higher than existing.
884 if (nExBit < static_cast<sal_uInt8>(nMode & ScRecalcMode::EMask))
885 SetMaskedRecalcMode( static_cast<ScRecalcMode>(nExBit));
886 }
887 SetCombinedBitsRecalcMode( nBits );
888 }
889
890
HasMatrixDoubleRefOps() const891 bool FormulaTokenArray::HasMatrixDoubleRefOps() const
892 {
893 if ( pRPN && nRPN )
894 {
895 // RPN-Interpreter simulation.
896 // Simply assumes a double as return value of each function.
897 std::unique_ptr<FormulaToken*[]> pStack(new FormulaToken* [nRPN]);
898 FormulaToken* pResult = new FormulaDoubleToken( 0.0 );
899 short sp = 0;
900 for ( auto t: RPNTokens() )
901 {
902 OpCode eOp = t->GetOpCode();
903 sal_uInt8 nParams = t->GetParamCount();
904 switch ( eOp )
905 {
906 case ocAdd :
907 case ocSub :
908 case ocMul :
909 case ocDiv :
910 case ocPow :
911 case ocPower :
912 case ocAmpersand :
913 case ocEqual :
914 case ocNotEqual :
915 case ocLess :
916 case ocGreater :
917 case ocLessEqual :
918 case ocGreaterEqual :
919 {
920 for ( sal_uInt8 k = nParams; k; k-- )
921 {
922 if ( sp >= k && pStack[sp-k]->GetType() == svDoubleRef )
923 {
924 pResult->Delete();
925 return true;
926 }
927 }
928 }
929 break;
930 default:
931 {
932 // added to avoid warnings
933 }
934 }
935 if ( eOp == ocPush || lcl_IsReference( eOp, t->GetType() ) )
936 pStack[sp++] = t;
937 else if (FormulaCompiler::IsOpCodeJumpCommand( eOp ))
938 { // ignore Jumps, pop previous Result (Condition)
939 if ( sp )
940 --sp;
941 }
942 else
943 { // pop parameters, push result
944 sp = sal::static_int_cast<short>( sp - nParams );
945 if ( sp < 0 )
946 {
947 SAL_WARN("formula.core", "FormulaTokenArray::HasMatrixDoubleRefOps: sp < 0" );
948 sp = 0;
949 }
950 pStack[sp++] = pResult;
951 }
952 }
953 pResult->Delete();
954 }
955
956 return false;
957 }
958
959 // --- Formula rewrite of a token array
960
isRewriteNeeded(OpCode eOp) const961 inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const
962 {
963 switch (eOp)
964 {
965 case ocGammaDist:
966 case ocPoissonDist:
967 case ocAddress:
968 case ocLogInv:
969 case ocLogNormDist:
970 case ocNormDist:
971 return true;
972 case ocMissing:
973 case ocLog:
974 return isPODF(); // rewrite only for PODF
975 case ocDBCount:
976 case ocDBCount2:
977 return isODFF(); // rewrite only for ODFF
978 default:
979 return false;
980 }
981 }
982
983 /*
984 fdo 81596
985 To be implemented yet:
986 ocExternal: ?
987 ocMacro: ?
988 ocIndex: INDEX() ?
989 */
isRewriteNeeded(OpCode eOp)990 inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp )
991 {
992 switch (eOp)
993 {
994 case ocIf:
995
996 case ocExternal:
997 case ocEuroConvert:
998 case ocMacro:
999
1000 case ocRound:
1001 case ocRoundUp:
1002 case ocRoundDown:
1003
1004 case ocIndex:
1005
1006 case ocCeil:
1007 case ocFloor:
1008
1009 case ocGammaDist:
1010 case ocFDist_LT:
1011 case ocPoissonDist:
1012 case ocNormDist:
1013 case ocLogInv:
1014 case ocLogNormDist:
1015 case ocHypGeomDist:
1016
1017 case ocDBCount:
1018 case ocDBCount2:
1019 return true;
1020
1021 default:
1022 return false;
1023 }
1024 }
1025
1026 namespace {
1027
1028 class FormulaMissingContext
1029 {
1030 public:
1031 const FormulaToken* mpFunc;
1032 int mnCurArg;
1033
Clear()1034 void Clear() { mpFunc = nullptr; mnCurArg = 0; }
1035 inline bool AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const;
1036 bool AddMissingExternal( FormulaTokenArray* pNewArr ) const;
1037 bool AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1038 void AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const;
1039 };
1040
1041 }
1042
AddMoreArgs(FormulaTokenArray * pNewArr,const MissingConvention & rConv) const1043 void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1044 {
1045 if ( !mpFunc )
1046 return;
1047
1048 switch (rConv.getConvention())
1049 {
1050 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1051 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1052 {
1053 switch (mpFunc->GetOpCode())
1054 {
1055 case ocGammaDist:
1056 if (mnCurArg == 2)
1057 {
1058 pNewArr->AddOpCode( ocSep );
1059 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1060 }
1061 break;
1062 case ocPoissonDist:
1063 if (mnCurArg == 1)
1064 {
1065 pNewArr->AddOpCode( ocSep );
1066 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1067 }
1068 break;
1069 case ocNormDist:
1070 if ( mnCurArg == 2 )
1071 {
1072 pNewArr->AddOpCode( ocSep );
1073 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1074 }
1075 break;
1076 case ocLogInv:
1077 case ocLogNormDist:
1078 if ( mnCurArg == 0 )
1079 {
1080 pNewArr->AddOpCode( ocSep );
1081 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1082 }
1083 if ( mnCurArg <= 1 )
1084 {
1085 pNewArr->AddOpCode( ocSep );
1086 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1087 }
1088 break;
1089 case ocLog:
1090 if ( rConv.isPODF() && mnCurArg == 0 )
1091 {
1092 pNewArr->AddOpCode( ocSep );
1093 pNewArr->AddDouble( 10.0 ); // 2nd, basis 10
1094 }
1095 break;
1096 default:
1097 break;
1098 }
1099 }
1100 break;
1101 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1102 {
1103 switch (mpFunc->GetOpCode())
1104 {
1105 case ocIf:
1106 if( mnCurArg == 0 )
1107 {
1108 // Excel needs at least two parameters in IF function
1109 pNewArr->AddOpCode( ocSep );
1110 pNewArr->AddOpCode( ocTrue ); // 2nd, true() as function
1111 pNewArr->AddOpCode( ocOpen ); // so the result is of logical type
1112 pNewArr->AddOpCode( ocClose ); // and survives roundtrip
1113 }
1114 break;
1115
1116 case ocEuroConvert:
1117 if ( mnCurArg == 2 )
1118 {
1119 pNewArr->AddOpCode( ocSep );
1120 pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false()
1121 }
1122 break;
1123
1124 case ocPoissonDist:
1125 if (mnCurArg == 1)
1126 {
1127 pNewArr->AddOpCode( ocSep );
1128 pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true()
1129 }
1130 break;
1131
1132 case ocGammaDist:
1133 case ocFDist_LT:
1134 case ocNormDist:
1135 if (mnCurArg == 2)
1136 {
1137 pNewArr->AddOpCode( ocSep );
1138 pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true()
1139 }
1140 break;
1141
1142 case ocLogInv:
1143 case ocLogNormDist:
1144 if ( mnCurArg == 0 )
1145 {
1146 pNewArr->AddOpCode( ocSep );
1147 pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0
1148 }
1149 if ( mnCurArg <= 1 )
1150 {
1151 pNewArr->AddOpCode( ocSep );
1152 pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0
1153 }
1154 break;
1155
1156 case ocHypGeomDist:
1157 if ( mnCurArg == 3 )
1158 {
1159 pNewArr->AddOpCode( ocSep );
1160 pNewArr->AddDouble( 0.0 ); // 5th, Cumulative = false()
1161 }
1162 break;
1163
1164 case ocRound:
1165 case ocRoundUp:
1166 case ocRoundDown:
1167 if( mnCurArg == 0 )
1168 {
1169 // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel
1170 pNewArr->AddOpCode( ocSep );
1171 pNewArr->AddDouble( 0.0 ); // 2nd, 0.0
1172 }
1173 break;
1174
1175 default:
1176 break;
1177 }
1178 }
1179 break;
1180 }
1181
1182 }
1183
AddDefaultArg(FormulaTokenArray * pNewArr,int nArg,double f) const1184 inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const
1185 {
1186 if (mnCurArg == nArg)
1187 {
1188 pNewArr->AddDouble( f );
1189 return true;
1190 }
1191 return false;
1192 }
1193
AddMissingExternal(FormulaTokenArray * pNewArr) const1194 bool FormulaMissingContext::AddMissingExternal( FormulaTokenArray *pNewArr ) const
1195 {
1196 // Only called for PODF, not ODFF. No need to distinguish.
1197
1198 const OUString &rName = mpFunc->GetExternal();
1199
1200 // initial (fast) check:
1201 sal_Unicode nLastChar = rName[ rName.getLength() - 1];
1202 if ( nLastChar != 't' && nLastChar != 'm' )
1203 return false;
1204
1205 if (rName.equalsIgnoreAsciiCase(
1206 "com.sun.star.sheet.addin.Analysis.getAccrint" ))
1207 {
1208 return AddDefaultArg( pNewArr, 4, 1000.0 );
1209 }
1210 if (rName.equalsIgnoreAsciiCase(
1211 "com.sun.star.sheet.addin.Analysis.getAccrintm" ))
1212 {
1213 return AddDefaultArg( pNewArr, 3, 1000.0 );
1214 }
1215 return false;
1216 }
1217
AddMissing(FormulaTokenArray * pNewArr,const MissingConvention & rConv) const1218 bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const MissingConvention & rConv ) const
1219 {
1220 if ( !mpFunc )
1221 return false;
1222
1223 bool bRet = false;
1224 const OpCode eOp = mpFunc->GetOpCode();
1225
1226 switch (rConv.getConvention())
1227 {
1228 case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF:
1229 {
1230 // Add for ODFF
1231 switch (eOp)
1232 {
1233 case ocAddress:
1234 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1235 default:
1236 break;
1237 }
1238 }
1239 break;
1240 case MissingConvention::FORMULA_MISSING_CONVENTION_PODF:
1241 {
1242 // Add for PODF
1243 switch (eOp)
1244 {
1245 case ocAddress:
1246 return AddDefaultArg( pNewArr, 2, 1.0 ); // abs
1247 case ocFixed:
1248 return AddDefaultArg( pNewArr, 1, 2.0 );
1249 case ocBetaDist:
1250 case ocBetaInv:
1251 case ocPMT:
1252 return AddDefaultArg( pNewArr, 3, 0.0 );
1253 case ocIpmt:
1254 case ocPpmt:
1255 return AddDefaultArg( pNewArr, 4, 0.0 );
1256 case ocPV:
1257 case ocFV:
1258 bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt
1259 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v
1260 break;
1261 case ocRate:
1262 bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt
1263 bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv
1264 bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type
1265 break;
1266 case ocExternal:
1267 return AddMissingExternal( pNewArr );
1268
1269 // --- more complex cases ---
1270
1271 case ocOffset:
1272 // FIXME: rather tough
1273 // if arg 3 (height) omitted, export arg1 (rows)
1274 break;
1275 default:
1276 break;
1277 }
1278 }
1279 break;
1280 case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML:
1281 {
1282 switch (eOp)
1283 {
1284 case ocExternal:
1285 return AddMissingExternal( pNewArr );
1286 default:
1287 break;
1288 }
1289 }
1290 break;
1291 }
1292
1293 return bRet;
1294 }
1295
NeedsPodfRewrite(const MissingConventionODF & rConv)1296 bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv )
1297 {
1298 for ( auto i: Tokens() )
1299 {
1300 if ( rConv.isRewriteNeeded( i->GetOpCode()))
1301 return true;
1302 }
1303 return false;
1304 }
1305
NeedsOoxmlRewrite()1306 bool FormulaTokenArray::NeedsOoxmlRewrite()
1307 {
1308 for ( auto i: Tokens() )
1309 {
1310 if ( MissingConventionOOXML::isRewriteNeeded( i->GetOpCode()))
1311 return true;
1312 }
1313 return false;
1314 }
1315
1316
RewriteMissing(const MissingConvention & rConv)1317 FormulaTokenArray * FormulaTokenArray::RewriteMissing( const MissingConvention & rConv )
1318 {
1319 const size_t nAlloc = 256;
1320 FormulaMissingContext aCtx[ nAlloc ];
1321
1322 /* TODO: with some effort we might be able to merge the two almost
1323 * identical function stacks into one and generalize things, otherwise
1324 * adding yet another "omit argument" would be copypasta. */
1325
1326 int aOpCodeAddressStack[ nAlloc ]; // use of ADDRESS() function
1327 const int nOmitAddressArg = 3; // ADDRESS() 4th parameter A1/R1C1
1328
1329 int aOpCodeDcountStack[ nAlloc ]; // use of DCOUNT()/DCOUNTA() function
1330 const int nOmitDcountArg = 1; // DCOUNT() and DCOUNTA() 2nd parameter DatabaseField if 0
1331
1332 sal_uInt16 nTokens = GetLen() + 1;
1333 FormulaMissingContext* pCtx = (nAlloc < nTokens ? new FormulaMissingContext[nTokens] : &aCtx[0]);
1334 int* pOcas = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeAddressStack[0]);
1335 int* pOcds = (nAlloc < nTokens ? new int[nTokens] : &aOpCodeDcountStack[0]);
1336 // Never go below 0, never use 0, mpFunc always NULL.
1337 pCtx[0].Clear();
1338 int nFn = 0;
1339 int nOcas = 0;
1340 int nOcds = 0;
1341
1342 FormulaTokenArray *pNewArr = new FormulaTokenArray;
1343 // At least ScRecalcMode::ALWAYS needs to be set.
1344 pNewArr->AddRecalcMode( GetRecalcMode());
1345
1346 FormulaTokenArrayPlainIterator aIter(*this);
1347 for ( FormulaToken *pCur = aIter.First(); pCur; pCur = aIter.Next() )
1348 {
1349 bool bAdd = true;
1350 // Don't write the expression of the new inserted ADDRESS() parameter.
1351 // Do NOT omit the new second parameter of INDIRECT() though. If that
1352 // was done for both, INDIRECT() actually could calculate different and
1353 // valid (but wrong) results with the then changed return value of
1354 // ADDRESS(). Better let it generate an error instead.
1355 for (int i = nOcas; i-- > 0 && bAdd; )
1356 {
1357 if (pCtx[ pOcas[ i ] ].mnCurArg == nOmitAddressArg)
1358 {
1359 // Omit everything except a trailing separator, the leading
1360 // separator is omitted below. The other way around would leave
1361 // an extraneous separator if no parameter followed.
1362 if (pOcas[ i ] != nFn || pCur->GetOpCode() != ocSep)
1363 bAdd = false;
1364 }
1365 }
1366 // Strip the 2nd argument (leaving empty) of DCOUNT() and DCOUNTA() if
1367 // it is 0.
1368 for (int i = nOcds; i-- > 0 && bAdd; )
1369 {
1370 if (pCtx[ pOcds[ i ] ].mnCurArg == nOmitDcountArg)
1371 {
1372 // Omit only a literal 0 value, nothing else.
1373 if (pOcds[ i ] == nFn && pCur->GetOpCode() == ocPush && pCur->GetType() == svDouble &&
1374 pCur->GetDouble() == 0.0)
1375 {
1376 // No other expression, between separators.
1377 FormulaToken* p = aIter.PeekPrevNoSpaces();
1378 if (p && p->GetOpCode() == ocSep)
1379 {
1380 p = aIter.PeekNextNoSpaces();
1381 if (p && p->GetOpCode() == ocSep)
1382 bAdd = false;
1383 }
1384 }
1385 }
1386 }
1387 switch ( pCur->GetOpCode() )
1388 {
1389 case ocOpen:
1390 {
1391 ++nFn; // all following operations on _that_ function
1392 pCtx[ nFn ].mpFunc = aIter.PeekPrevNoSpaces();
1393 pCtx[ nFn ].mnCurArg = 0;
1394 if (rConv.isPODF() && pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress)
1395 pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF
1396 else if ((rConv.isODFF() || rConv.isOOXML()) && pCtx[ nFn ].mpFunc)
1397 {
1398 OpCode eOp = pCtx[ nFn ].mpFunc->GetOpCode();
1399 if (eOp == ocDBCount || eOp == ocDBCount2)
1400 pOcds[ nOcds++ ] = nFn; // entering DCOUNT() or DCOUNTA() if ODFF or OOXML
1401 }
1402 }
1403 break;
1404 case ocClose:
1405 pCtx[ nFn ].AddMoreArgs( pNewArr, rConv );
1406 SAL_WARN_IF(nFn <= 0, "formula.core", "FormulaTokenArray::RewriteMissing: underflow");
1407 if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn)
1408 --nOcas; // leaving ADDRESS()
1409 else if (nOcds > 0 && pOcds[ nOcds-1 ] == nFn)
1410 --nOcds; // leaving DCOUNT() or DCOUNTA()
1411 if (nFn > 0)
1412 --nFn;
1413 break;
1414 case ocSep:
1415 pCtx[ nFn ].mnCurArg++;
1416 // Omit leading separator of ADDRESS() parameter.
1417 if (nOcas && pOcas[ nOcas-1 ] == nFn && pCtx[ nFn ].mnCurArg == nOmitAddressArg)
1418 {
1419 bAdd = false;
1420 }
1421 break;
1422 case ocMissing:
1423 if ( bAdd )
1424 bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv );
1425 break;
1426 default:
1427 break;
1428 }
1429 if (bAdd)
1430 {
1431 OpCode eOp = pCur->GetOpCode();
1432 if ( ( eOp == ocCeil || eOp == ocFloor ||
1433 ( eOp == ocLogNormDist && pCur->GetByte() == 4 ) ) &&
1434 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1435 {
1436 switch ( eOp )
1437 {
1438 case ocCeil :
1439 eOp = ocCeil_Math;
1440 break;
1441 case ocFloor :
1442 eOp = ocFloor_Math;
1443 break;
1444 case ocLogNormDist :
1445 eOp = ocLogNormDist_MS;
1446 break;
1447 default :
1448 eOp = ocNone;
1449 break;
1450 }
1451 FormulaToken *pToken = new FormulaToken( svByte, eOp );
1452 pNewArr->Add( pToken );
1453 }
1454 else if ( eOp == ocHypGeomDist &&
1455 rConv.getConvention() == MissingConvention::FORMULA_MISSING_CONVENTION_OOXML )
1456 {
1457 FormulaToken *pToken = new FormulaToken( svByte, ocHypGeomDist_MS );
1458 pNewArr->Add( pToken );
1459 }
1460 else
1461 pNewArr->AddToken( *pCur );
1462 }
1463 }
1464
1465 if (pOcds != &aOpCodeDcountStack[0])
1466 delete [] pOcds;
1467 if (pOcas != &aOpCodeAddressStack[0])
1468 delete [] pOcas;
1469 if (pCtx != &aCtx[0])
1470 delete [] pCtx;
1471
1472 return pNewArr;
1473 }
1474
MayReferenceFollow()1475 bool FormulaTokenArray::MayReferenceFollow()
1476 {
1477 if ( pCode && nLen > 0 )
1478 {
1479 // ignore trailing spaces
1480 sal_uInt16 i = nLen - 1;
1481 while ( i > 0 && pCode[i]->GetOpCode() == SC_OPCODE_SPACES )
1482 {
1483 --i;
1484 }
1485 if ( i > 0 || pCode[i]->GetOpCode() != SC_OPCODE_SPACES )
1486 {
1487 OpCode eOp = pCode[i]->GetOpCode();
1488 if ( (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_BIN_OP ) ||
1489 (SC_OPCODE_START_UN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP ) ||
1490 eOp == SC_OPCODE_OPEN || eOp == SC_OPCODE_SEP )
1491 {
1492 return true;
1493 }
1494 }
1495 }
1496 return false;
1497 }
AddOpCode(OpCode eOp)1498 FormulaToken* FormulaTokenArray::AddOpCode( OpCode eOp )
1499 {
1500 FormulaToken* pRet = nullptr;
1501 switch ( eOp )
1502 {
1503 case ocOpen:
1504 case ocClose:
1505 case ocSep:
1506 case ocArrayOpen:
1507 case ocArrayClose:
1508 case ocArrayRowSep:
1509 case ocArrayColSep:
1510 pRet = new FormulaToken( svSep,eOp );
1511 break;
1512 case ocIf:
1513 case ocIfError:
1514 case ocIfNA:
1515 case ocChoose:
1516 {
1517 short nJump[FORMULA_MAXJUMPCOUNT + 1];
1518 if ( eOp == ocIf )
1519 nJump[ 0 ] = 3;
1520 else if ( eOp == ocChoose )
1521 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
1522 else
1523 nJump[ 0 ] = 2;
1524 pRet = new FormulaJumpToken( eOp, nJump );
1525 }
1526 break;
1527 default:
1528 pRet = new FormulaByteToken( eOp, 0, ParamClass::Unknown );
1529 break;
1530 }
1531 return Add( pRet );
1532 }
1533
ReinternStrings(svl::SharedStringPool & rPool)1534 void FormulaTokenArray::ReinternStrings( svl::SharedStringPool& rPool )
1535 {
1536 for (auto i: Tokens())
1537 {
1538 switch (i->GetType())
1539 {
1540 case svString:
1541 i->SetString( rPool.intern( i->GetString().getString()));
1542 break;
1543 default:
1544 ; // nothing
1545 }
1546 }
1547 }
1548
1549
1550 /*----------------------------------------------------------------------*/
1551
Item(const FormulaTokenArray * pArray,short pc,short stop)1552 FormulaTokenIterator::Item::Item(const FormulaTokenArray* pArray, short pc, short stop) :
1553 pArr(pArray), nPC(pc), nStop(stop)
1554 {
1555 }
1556
FormulaTokenIterator(const FormulaTokenArray & rArr)1557 FormulaTokenIterator::FormulaTokenIterator( const FormulaTokenArray& rArr )
1558 {
1559 Push( &rArr );
1560 }
1561
~FormulaTokenIterator()1562 FormulaTokenIterator::~FormulaTokenIterator()
1563 {
1564 }
1565
Push(const FormulaTokenArray * pArr)1566 void FormulaTokenIterator::Push( const FormulaTokenArray* pArr )
1567 {
1568 FormulaTokenIterator::Item item(pArr, -1, SHRT_MAX);
1569
1570 maStack.push_back(item);
1571 }
1572
Pop()1573 void FormulaTokenIterator::Pop()
1574 {
1575 maStack.pop_back();
1576 }
1577
Reset()1578 void FormulaTokenIterator::Reset()
1579 {
1580 while( maStack.size() > 1 )
1581 maStack.pop_back();
1582
1583 maStack.back().nPC = -1;
1584 }
1585
GetNextName()1586 FormulaToken* FormulaTokenArrayPlainIterator::GetNextName()
1587 {
1588 if( mpFTA->GetArray() )
1589 {
1590 while ( mnIndex < mpFTA->GetLen() )
1591 {
1592 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1593 if( t->GetType() == svIndex )
1594 return t;
1595 }
1596 }
1597 return nullptr;
1598 }
1599
Next()1600 const FormulaToken* FormulaTokenIterator::Next()
1601 {
1602 const FormulaToken* t = GetNonEndOfPathToken( ++maStack.back().nPC );
1603 if( !t && maStack.size() > 1 )
1604 {
1605 Pop();
1606 t = Next();
1607 }
1608 return t;
1609 }
1610
PeekNextOperator()1611 const FormulaToken* FormulaTokenIterator::PeekNextOperator()
1612 {
1613 const FormulaToken* t = nullptr;
1614 short nIdx = maStack.back().nPC;
1615 for (;;)
1616 {
1617 t = GetNonEndOfPathToken( ++nIdx);
1618 if (t == nullptr || t->GetOpCode() != ocPush)
1619 break; // ignore operands
1620 }
1621 if (!t && maStack.size() > 1)
1622 {
1623 FormulaTokenIterator::Item aHere = maStack.back();
1624 maStack.pop_back();
1625 t = PeekNextOperator();
1626 maStack.push_back(aHere);
1627 }
1628 return t;
1629 }
1630
1631 //! The nPC counts after a Push() are -1
1632
Jump(short nStart,short nNext,short nStop)1633 void FormulaTokenIterator::Jump( short nStart, short nNext, short nStop )
1634 {
1635 maStack.back().nPC = nNext;
1636 if( nStart != nNext )
1637 {
1638 Push( maStack.back().pArr );
1639 maStack.back().nPC = nStart;
1640 maStack.back().nStop = nStop;
1641 }
1642 }
1643
ReInit(const FormulaTokenArray & rArr)1644 void FormulaTokenIterator::ReInit( const FormulaTokenArray& rArr )
1645 {
1646 maStack.clear();
1647 Push( &rArr );
1648 }
1649
GetNonEndOfPathToken(short nIdx) const1650 const FormulaToken* FormulaTokenIterator::GetNonEndOfPathToken( short nIdx ) const
1651 {
1652 FormulaTokenIterator::Item cur = maStack.back();
1653
1654 if (nIdx < cur.pArr->GetCodeLen() && nIdx < cur.nStop)
1655 {
1656 const FormulaToken* t = cur.pArr->GetCode()[ nIdx ];
1657 // such an OpCode ends an IF() or CHOOSE() path
1658 return (t->GetOpCode() == ocSep || t->GetOpCode() == ocClose) ? nullptr : t;
1659 }
1660 return nullptr;
1661 }
1662
IsEndOfPath() const1663 bool FormulaTokenIterator::IsEndOfPath() const
1664 {
1665 return GetNonEndOfPathToken( maStack.back().nPC + 1) == nullptr;
1666 }
1667
GetNextReference()1668 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReference()
1669 {
1670 while( mnIndex < mpFTA->GetLen() )
1671 {
1672 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1673 switch( t->GetType() )
1674 {
1675 case svSingleRef:
1676 case svDoubleRef:
1677 case svExternalSingleRef:
1678 case svExternalDoubleRef:
1679 return t;
1680 default:
1681 {
1682 // added to avoid warnings
1683 }
1684 }
1685 }
1686 return nullptr;
1687 }
1688
GetNextColRowName()1689 FormulaToken* FormulaTokenArrayPlainIterator::GetNextColRowName()
1690 {
1691 while( mnIndex < mpFTA->GetLen() )
1692 {
1693 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1694 if ( t->GetOpCode() == ocColRowName )
1695 return t;
1696 }
1697 return nullptr;
1698 }
1699
GetNextReferenceRPN()1700 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceRPN()
1701 {
1702 while( mnIndex < mpFTA->GetCodeLen() )
1703 {
1704 FormulaToken* t = mpFTA->GetCode()[ mnIndex++ ];
1705 switch( t->GetType() )
1706 {
1707 case svSingleRef:
1708 case svDoubleRef:
1709 case svExternalSingleRef:
1710 case svExternalDoubleRef:
1711 return t;
1712 default:
1713 {
1714 // added to avoid warnings
1715 }
1716 }
1717 }
1718 return nullptr;
1719 }
1720
GetNextReferenceOrName()1721 FormulaToken* FormulaTokenArrayPlainIterator::GetNextReferenceOrName()
1722 {
1723 if( mpFTA->GetArray() )
1724 {
1725 while ( mnIndex < mpFTA->GetLen() )
1726 {
1727 FormulaToken* t = mpFTA->GetArray()[ mnIndex++ ];
1728 switch( t->GetType() )
1729 {
1730 case svSingleRef:
1731 case svDoubleRef:
1732 case svIndex:
1733 case svExternalSingleRef:
1734 case svExternalDoubleRef:
1735 case svExternalName:
1736 return t;
1737 default:
1738 {
1739 // added to avoid warnings
1740 }
1741 }
1742 }
1743 }
1744 return nullptr;
1745 }
1746
Next()1747 FormulaToken* FormulaTokenArrayPlainIterator::Next()
1748 {
1749 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1750 return mpFTA->GetArray()[ mnIndex++ ];
1751 else
1752 return nullptr;
1753 }
1754
NextNoSpaces()1755 FormulaToken* FormulaTokenArrayPlainIterator::NextNoSpaces()
1756 {
1757 if( mpFTA->GetArray() )
1758 {
1759 while( (mnIndex < mpFTA->GetLen()) && (mpFTA->GetArray()[ mnIndex ]->GetOpCode() == ocSpaces) )
1760 ++mnIndex;
1761 if( mnIndex < mpFTA->GetLen() )
1762 return mpFTA->GetArray()[ mnIndex++ ];
1763 }
1764 return nullptr;
1765 }
1766
NextRPN()1767 FormulaToken* FormulaTokenArrayPlainIterator::NextRPN()
1768 {
1769 if( mpFTA->GetCode() && mnIndex < mpFTA->GetCodeLen() )
1770 return mpFTA->GetCode()[ mnIndex++ ];
1771 else
1772 return nullptr;
1773 }
1774
PrevRPN()1775 FormulaToken* FormulaTokenArrayPlainIterator::PrevRPN()
1776 {
1777 if( mpFTA->GetCode() && mnIndex )
1778 return mpFTA->GetCode()[ --mnIndex ];
1779 else
1780 return nullptr;
1781 }
1782
PeekNext()1783 FormulaToken* FormulaTokenArrayPlainIterator::PeekNext()
1784 {
1785 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1786 return mpFTA->GetArray()[ mnIndex ];
1787 else
1788 return nullptr;
1789 }
1790
PeekNextNoSpaces() const1791 FormulaToken* FormulaTokenArrayPlainIterator::PeekNextNoSpaces() const
1792 {
1793 if( mpFTA->GetArray() && mnIndex < mpFTA->GetLen() )
1794 {
1795 sal_uInt16 j = mnIndex;
1796 while ( j < mpFTA->GetLen() && mpFTA->GetArray()[j]->GetOpCode() == ocSpaces )
1797 j++;
1798 if ( j < mpFTA->GetLen() )
1799 return mpFTA->GetArray()[ j ];
1800 else
1801 return nullptr;
1802 }
1803 else
1804 return nullptr;
1805 }
1806
PeekPrevNoSpaces() const1807 FormulaToken* FormulaTokenArrayPlainIterator::PeekPrevNoSpaces() const
1808 {
1809 if( mpFTA->GetArray() && mnIndex > 1 )
1810 {
1811 sal_uInt16 j = mnIndex - 2;
1812 while ( mpFTA->GetArray()[j]->GetOpCode() == ocSpaces && j > 0 )
1813 j--;
1814 if ( j > 0 || mpFTA->GetArray()[j]->GetOpCode() != ocSpaces )
1815 return mpFTA->GetArray()[ j ];
1816 else
1817 return nullptr;
1818 }
1819 else
1820 return nullptr;
1821 }
1822
AfterRemoveToken(sal_uInt16 nOffset,sal_uInt16 nCount)1823 void FormulaTokenArrayPlainIterator::AfterRemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount )
1824 {
1825 const sal_uInt16 nStop = std::min( static_cast<sal_uInt16>(nOffset + nCount), mpFTA->GetLen());
1826
1827 if (mnIndex >= nOffset)
1828 {
1829 if (mnIndex < nStop)
1830 mnIndex = nOffset + 1;
1831 else
1832 mnIndex -= nStop - nOffset;
1833 }
1834 }
1835
1836 // real implementations of virtual functions
1837
1838
GetDouble() const1839 double FormulaDoubleToken::GetDouble() const { return fDouble; }
GetDoubleAsReference()1840 double & FormulaDoubleToken::GetDoubleAsReference() { return fDouble; }
1841
GetDoubleType() const1842 sal_Int16 FormulaDoubleToken::GetDoubleType() const
1843 {
1844 // This is a plain double value without type information, don't emit a
1845 // warning via FormulaToken::GetDoubleType().
1846 return 0;
1847 }
1848
operator ==(const FormulaToken & r) const1849 bool FormulaDoubleToken::operator==( const FormulaToken& r ) const
1850 {
1851 return FormulaToken::operator==( r ) && fDouble == r.GetDouble();
1852 }
1853
GetDoubleType() const1854 sal_Int16 FormulaTypedDoubleToken::GetDoubleType() const
1855 {
1856 return mnType;
1857 }
1858
SetDoubleType(sal_Int16 nType)1859 void FormulaTypedDoubleToken::SetDoubleType( sal_Int16 nType )
1860 {
1861 mnType = nType;
1862 }
1863
operator ==(const FormulaToken & r) const1864 bool FormulaTypedDoubleToken::operator==( const FormulaToken& r ) const
1865 {
1866 return FormulaDoubleToken::operator==( r ) && mnType == r.GetDoubleType();
1867 }
1868
FormulaStringToken(const svl::SharedString & r)1869 FormulaStringToken::FormulaStringToken( const svl::SharedString& r ) :
1870 FormulaToken( svString ), maString( r )
1871 {
1872 }
1873
FormulaStringToken(const FormulaStringToken & r)1874 FormulaStringToken::FormulaStringToken( const FormulaStringToken& r ) :
1875 FormulaToken( r ), maString( r.maString ) {}
1876
Clone() const1877 FormulaToken* FormulaStringToken::Clone() const
1878 {
1879 return new FormulaStringToken(*this);
1880 }
1881
GetString() const1882 const svl::SharedString & FormulaStringToken::GetString() const
1883 {
1884 return maString;
1885 }
1886
SetString(const svl::SharedString & rStr)1887 void FormulaStringToken::SetString( const svl::SharedString& rStr )
1888 {
1889 maString = rStr;
1890 }
1891
operator ==(const FormulaToken & r) const1892 bool FormulaStringToken::operator==( const FormulaToken& r ) const
1893 {
1894 return FormulaToken::operator==( r ) && maString == r.GetString();
1895 }
1896
FormulaStringOpToken(OpCode e,const svl::SharedString & r)1897 FormulaStringOpToken::FormulaStringOpToken( OpCode e, const svl::SharedString& r ) :
1898 FormulaByteToken( e, 0, svString, ParamClass::Unknown ), maString( r ) {}
1899
FormulaStringOpToken(const FormulaStringOpToken & r)1900 FormulaStringOpToken::FormulaStringOpToken( const FormulaStringOpToken& r ) :
1901 FormulaByteToken( r ), maString( r.maString ) {}
1902
Clone() const1903 FormulaToken* FormulaStringOpToken::Clone() const
1904 {
1905 return new FormulaStringOpToken(*this);
1906 }
1907
GetString() const1908 const svl::SharedString & FormulaStringOpToken::GetString() const
1909 {
1910 return maString;
1911 }
1912
SetString(const svl::SharedString & rStr)1913 void FormulaStringOpToken::SetString( const svl::SharedString& rStr )
1914 {
1915 maString = rStr;
1916 }
1917
operator ==(const FormulaToken & r) const1918 bool FormulaStringOpToken::operator==( const FormulaToken& r ) const
1919 {
1920 return FormulaByteToken::operator==( r ) && maString == r.GetString();
1921 }
1922
GetIndex() const1923 sal_uInt16 FormulaIndexToken::GetIndex() const { return nIndex; }
SetIndex(sal_uInt16 n)1924 void FormulaIndexToken::SetIndex( sal_uInt16 n ) { nIndex = n; }
GetSheet() const1925 sal_Int16 FormulaIndexToken::GetSheet() const { return mnSheet; }
SetSheet(sal_Int16 n)1926 void FormulaIndexToken::SetSheet( sal_Int16 n ) { mnSheet = n; }
operator ==(const FormulaToken & r) const1927 bool FormulaIndexToken::operator==( const FormulaToken& r ) const
1928 {
1929 return FormulaToken::operator==( r ) && nIndex == r.GetIndex() &&
1930 mnSheet == r.GetSheet();
1931 }
GetExternal() const1932 const OUString& FormulaExternalToken::GetExternal() const { return aExternal; }
operator ==(const FormulaToken & r) const1933 bool FormulaExternalToken::operator==( const FormulaToken& r ) const
1934 {
1935 return FormulaByteToken::operator==( r ) && aExternal == r.GetExternal();
1936 }
1937
1938
GetError() const1939 FormulaError FormulaErrorToken::GetError() const { return nError; }
SetError(FormulaError nErr)1940 void FormulaErrorToken::SetError( FormulaError nErr ) { nError = nErr; }
operator ==(const FormulaToken & r) const1941 bool FormulaErrorToken::operator==( const FormulaToken& r ) const
1942 {
1943 return FormulaToken::operator==( r ) &&
1944 nError == static_cast< const FormulaErrorToken & >(r).GetError();
1945 }
GetDouble() const1946 double FormulaMissingToken::GetDouble() const { return 0.0; }
1947
GetString() const1948 const svl::SharedString & FormulaMissingToken::GetString() const
1949 {
1950 return svl::SharedString::getEmptyString();
1951 }
1952
operator ==(const FormulaToken & r) const1953 bool FormulaMissingToken::operator==( const FormulaToken& r ) const
1954 {
1955 return FormulaToken::operator==( r );
1956 }
1957
1958
operator ==(const FormulaToken & r) const1959 bool FormulaUnknownToken::operator==( const FormulaToken& r ) const
1960 {
1961 return FormulaToken::operator==( r );
1962 }
1963
1964
1965 } // formula
1966
1967
1968 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1969