xref: /core/basic/source/sbx/sbxvalue.cxx (revision 010e99c7)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <math.h>
23 #include <string_view>
24 
25 #include <o3tl/float_int_conversion.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/stream.hxx>
28 #include <sal/log.hxx>
29 
30 #include <basic/sbx.hxx>
31 #include <sbunoobj.hxx>
32 #include "sbxconv.hxx"
33 #include <runtime.hxx>
34 
35 
36 ///////////////////////////// constructors
37 
38 SbxValue::SbxValue()
39 {
40     aData.eType = SbxEMPTY;
41 }
42 
43 SbxValue::SbxValue( SbxDataType t )
44 {
45     int n = t & 0x0FFF;
46 
47     if( n == SbxVARIANT )
48         n = SbxEMPTY;
49     else
50         SetFlag( SbxFlagBits::Fixed );
51     aData.clear(SbxDataType( n ));
52 }
53 
54 SbxValue::SbxValue( const SbxValue& r )
55     : SvRefBase( r ), SbxBase( r )
56 {
57     if( !r.CanRead() )
58     {
59         SetError( ERRCODE_BASIC_PROP_WRITEONLY );
60         if( !IsFixed() )
61             aData.eType = SbxNULL;
62     }
63     else
64     {
65         const_cast<SbxValue*>(&r)->Broadcast( SfxHintId::BasicDataWanted );
66         aData = r.aData;
67         // Copy pointer, increment references
68         switch( aData.eType )
69         {
70             case SbxSTRING:
71                 if( aData.pOUString )
72                     aData.pOUString = new OUString( *aData.pOUString );
73                 break;
74             case SbxOBJECT:
75                 if( aData.pObj )
76                     aData.pObj->AddFirstRef();
77                 break;
78             case SbxDECIMAL:
79                 if( aData.pDecimal )
80                     aData.pDecimal->addRef();
81                 break;
82             default: break;
83         }
84     }
85 }
86 
87 SbxValue& SbxValue::operator=( const SbxValue& r )
88 {
89     if( &r != this )
90     {
91         if( !CanWrite() )
92             SetError( ERRCODE_BASIC_PROP_READONLY );
93         else
94         {
95             // string -> byte array
96             if( IsFixed() && (aData.eType == SbxOBJECT)
97                 && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
98                 && (r.aData.eType == SbxSTRING) )
99             {
100                 OUString aStr = r.GetOUString();
101                 SbxArray* pArr = StringToByteArray(aStr);
102                 PutObject(pArr);
103                 return *this;
104             }
105             // byte array -> string
106             if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
107                 && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
108                 && (aData.eType == SbxSTRING) )
109             {
110                 SbxBase* pObj = r.GetObject();
111                 SbxArray* pArr = dynamic_cast<SbxArray*>( pObj );
112                 if( pArr )
113                 {
114                     OUString aStr = ByteArrayToString( pArr );
115                     PutString(aStr);
116                     return *this;
117                 }
118             }
119             // Readout the content of the variables
120             SbxValues aNew;
121             if( IsFixed() )
122                 // then the type has to match
123                 aNew.eType = aData.eType;
124             else if( r.IsFixed() )
125                 // Source fixed: copy the type
126                 aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
127             else
128                 // both variant: then don't care
129                 aNew.eType = SbxVARIANT;
130             if( r.Get( aNew ) )
131                 Put( aNew );
132         }
133     }
134     return *this;
135 }
136 
137 SbxValue::~SbxValue()
138 {
139     SetFlag( SbxFlagBits::Write );
140     // cid#1486004 silence Uncaught exception
141     suppress_fun_call_w_exception(SbxValue::Clear());
142 }
143 
144 void SbxValue::Clear()
145 {
146     switch( aData.eType )
147     {
148         case SbxNULL:
149         case SbxEMPTY:
150         case SbxVOID:
151             break;
152         case SbxSTRING:
153             delete aData.pOUString; aData.pOUString = nullptr;
154             break;
155         case SbxOBJECT:
156             if( aData.pObj )
157             {
158                 if( aData.pObj != this )
159                 {
160                     SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
161                     SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
162                     bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
163                     if ( !bParentProp )
164                         aData.pObj->ReleaseRef();
165                 }
166                 aData.pObj = nullptr;
167             }
168             break;
169         case SbxDECIMAL:
170             releaseDecimalPtr( aData.pDecimal );
171             break;
172         case SbxDATAOBJECT:
173             aData.pData = nullptr; break;
174         default:
175         {
176             SbxValues aEmpty;
177             aEmpty.clear(GetType());
178             Put( aEmpty );
179         }
180     }
181 }
182 
183 // Dummy
184 
185 void SbxValue::Broadcast( SfxHintId )
186 {}
187 
188 //////////////////////////// Readout data
189 
190 // Detect the "right" variables. If it is an object, will be addressed either
191 // the object itself or its default property.
192 // If the variable contain a variable or an object, this will be
193 // addressed.
194 
195 SbxValue* SbxValue::TheRealValue( bool bObjInObjError ) const
196 {
197     SbxValue* p = const_cast<SbxValue*>(this);
198     for( ;; )
199     {
200         SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
201         if( t == SbxOBJECT )
202         {
203             // The block contains an object or a variable
204             SbxObject* pObj = dynamic_cast<SbxObject*>( p->aData.pObj );
205             if( pObj )
206             {
207                 // Has the object a default property?
208                 SbxVariable* pDflt = pObj->GetDfltProperty();
209 
210                 // If this is an object and contains itself,
211                 // we cannot access on it
212                 // The old condition to set an error is not correct,
213                 // because e.g. a regular variant variable with an object
214                 // could be affected if another value should be assigned.
215                 // Therefore with flag.
216                 if( bObjInObjError && !pDflt &&
217                     static_cast<SbxValue*>(pObj)->aData.eType == SbxOBJECT &&
218                     static_cast<SbxValue*>(pObj)->aData.pObj == pObj )
219                 {
220 #if !HAVE_FEATURE_SCRIPTING
221                     const bool bSuccess = false;
222 #else
223                     bool bSuccess = handleToStringForCOMObjects( pObj, p );
224 #endif
225                     if( !bSuccess )
226                     {
227                         SetError( ERRCODE_BASIC_BAD_PROP_VALUE );
228                         p = nullptr;
229                     }
230                 }
231                 else if( pDflt )
232                     p = pDflt;
233                 break;
234             }
235             // Did we have an array?
236             SbxArray* pArray = dynamic_cast<SbxArray*>( p->aData.pObj );
237             if( pArray )
238             {
239                 // When indicated get the parameter
240                 SbxArray* pPar = nullptr;
241                 SbxVariable* pVar = dynamic_cast<SbxVariable*>( p );
242                 if( pVar )
243                     pPar = pVar->GetParameters();
244                 if( pPar )
245                 {
246                     // Did we have a dimensioned array?
247                     SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( p->aData.pObj );
248                     if( pDimArray )
249                         p = pDimArray->Get( pPar );
250                     else
251                         p = pArray->Get(pPar->Get(1)->GetInteger());
252                     break;
253                 }
254             }
255             // Otherwise guess a SbxValue
256             SbxValue* pVal = dynamic_cast<SbxValue*>( p->aData.pObj );
257             if( pVal )
258                 p = pVal;
259             else
260                 break;
261         }
262         else
263             break;
264     }
265     return p;
266 }
267 
268 bool SbxValue::Get( SbxValues& rRes ) const
269 {
270     bool bRes = false;
271     ErrCode eOld = GetError();
272     if( eOld != ERRCODE_NONE )
273         ResetError();
274     if( !CanRead() )
275     {
276         SetError( ERRCODE_BASIC_PROP_WRITEONLY );
277         rRes.pObj = nullptr;
278     }
279     else
280     {
281         // If an object or a VARIANT is requested, don't search the real values
282         SbxValue* p = const_cast<SbxValue*>(this);
283         if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
284             p = TheRealValue( true );
285         if( p )
286         {
287             p->Broadcast( SfxHintId::BasicDataWanted );
288             switch( rRes.eType )
289             {
290                 case SbxEMPTY:
291                 case SbxVOID:
292                 case SbxNULL:    break;
293                 case SbxVARIANT: rRes = p->aData; break;
294                 case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
295                 case SbxLONG:    rRes.nLong = ImpGetLong( &p->aData ); break;
296                 case SbxSALINT64:   rRes.nInt64 = ImpGetInt64( &p->aData ); break;
297                 case SbxSALUINT64:  rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
298                 case SbxSINGLE:  rRes.nSingle = ImpGetSingle( &p->aData ); break;
299                 case SbxDOUBLE:  rRes.nDouble = ImpGetDouble( &p->aData ); break;
300                 case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
301                 case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
302                 case SbxDATE:    rRes.nDouble = ImpGetDate( &p->aData ); break;
303                 case SbxBOOL:
304                     rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
305                         ImpGetBool( &p->aData ) );
306                     break;
307                 case SbxCHAR:    rRes.nChar = ImpGetChar( &p->aData ); break;
308                 case SbxBYTE:    rRes.nByte = ImpGetByte( &p->aData ); break;
309                 case SbxUSHORT:  rRes.nUShort = ImpGetUShort( &p->aData ); break;
310                 case SbxULONG:   rRes.nULong = ImpGetULong( &p->aData ); break;
311                 case SbxLPSTR:
312                 case SbxSTRING:  p->aPic = ImpGetString( &p->aData );
313                                  rRes.pOUString = &p->aPic; break;
314                 case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
315                                     rRes.pOUString = &p->aPic; break;
316                 case SbxINT:
317                     rRes.nInt = static_cast<int>(ImpGetLong( &p->aData ));
318                     break;
319                 case SbxUINT:
320                     rRes.nUInt = static_cast<int>(ImpGetULong( &p->aData ));
321                     break;
322                 case SbxOBJECT:
323                     if( p->aData.eType == SbxOBJECT )
324                         rRes.pObj = p->aData.pObj;
325                     else
326                     {
327                         SetError( ERRCODE_BASIC_NO_OBJECT );
328                         rRes.pObj = nullptr;
329                     }
330                     break;
331                 default:
332                     if( p->aData.eType == rRes.eType )
333                         rRes = p->aData;
334                     else
335                     {
336                         SetError( ERRCODE_BASIC_CONVERSION );
337                         rRes.pObj = nullptr;
338                     }
339             }
340         }
341         else
342         {
343             // Object contained itself
344             SbxDataType eTemp = rRes.eType;
345             rRes.clear(eTemp);
346         }
347     }
348     if( !IsError() )
349     {
350         bRes = true;
351         if( eOld != ERRCODE_NONE )
352             SetError( eOld );
353     }
354     return bRes;
355 }
356 
357 SbxValues SbxValue::Get(SbxDataType t) const
358 {
359     SbxValues aRes(t);
360     Get(aRes);
361     return aRes;
362 }
363 
364 const OUString& SbxValue::GetCoreString() const
365 {
366     SbxValues aRes(SbxCoreSTRING);
367     if( Get( aRes ) )
368     {
369         const_cast<SbxValue*>(this)->aToolString = *aRes.pOUString;
370     }
371     else
372     {
373         const_cast<SbxValue*>(this)->aToolString.clear();
374     }
375     return aToolString;
376 }
377 
378 OUString SbxValue::GetOUString() const
379 {
380     OUString aResult;
381     SbxValues aRes(SbxSTRING);
382     if( Get( aRes ) )
383     {
384         aResult = *aRes.pOUString;
385     }
386     return aResult;
387 }
388 
389 //////////////////////////// Write data
390 
391 bool SbxValue::Put( const SbxValues& rVal )
392 {
393     bool bRes = false;
394     ErrCode eOld = GetError();
395     if( eOld != ERRCODE_NONE )
396         ResetError();
397     if( !CanWrite() )
398         SetError( ERRCODE_BASIC_PROP_READONLY );
399     else if( rVal.eType & 0xF000 )
400         SetError( ERRCODE_BASIC_BAD_ARGUMENT );
401     else
402     {
403         // If an object is requested, don't search the real values
404         SbxValue* p = this;
405         if( rVal.eType != SbxOBJECT )
406             p = TheRealValue( false );  // Don't allow an error here
407         if( p )
408         {
409             if( !p->CanWrite() )
410                 SetError( ERRCODE_BASIC_PROP_READONLY );
411             else if( p->IsFixed() || p->SetType( static_cast<SbxDataType>( rVal.eType & 0x0FFF ) ) )
412               switch( rVal.eType & 0x0FFF )
413             {
414                 case SbxEMPTY:
415                 case SbxVOID:
416                 case SbxNULL:       break;
417                 case SbxINTEGER:    ImpPutInteger( &p->aData, rVal.nInteger ); break;
418                 case SbxLONG:       ImpPutLong( &p->aData, rVal.nLong ); break;
419                 case SbxSALINT64:   ImpPutInt64( &p->aData, rVal.nInt64 ); break;
420                 case SbxSALUINT64:  ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
421                 case SbxSINGLE:     ImpPutSingle( &p->aData, rVal.nSingle ); break;
422                 case SbxDOUBLE:     ImpPutDouble( &p->aData, rVal.nDouble ); break;
423                 case SbxCURRENCY:   ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
424                 case SbxDECIMAL:    ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
425                 case SbxDATE:       ImpPutDate( &p->aData, rVal.nDouble ); break;
426                 case SbxBOOL:       ImpPutBool( &p->aData, rVal.nInteger ); break;
427                 case SbxCHAR:       ImpPutChar( &p->aData, rVal.nChar ); break;
428                 case SbxBYTE:       ImpPutByte( &p->aData, rVal.nByte ); break;
429                 case SbxUSHORT:     ImpPutUShort( &p->aData, rVal.nUShort ); break;
430                 case SbxULONG:      ImpPutULong( &p->aData, rVal.nULong ); break;
431                 case SbxLPSTR:
432                 case SbxSTRING:     ImpPutString( &p->aData, rVal.pOUString ); break;
433                 case SbxINT:
434                     ImpPutLong( &p->aData, static_cast<sal_Int32>(rVal.nInt) );
435                     break;
436                 case SbxUINT:
437                     ImpPutULong( &p->aData, static_cast<sal_uInt32>(rVal.nUInt) );
438                     break;
439                 case SbxOBJECT:
440                     if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
441                     {
442                         // is already inside
443                         if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
444                             break;
445 
446                         // Delete only the value part!
447                         p->SbxValue::Clear();
448 
449                         // real assignment
450                         p->aData.pObj = rVal.pObj;
451 
452                         // if necessary increment Ref-Count
453                         if( p->aData.pObj && p->aData.pObj != p )
454                         {
455                             if ( p != this )
456                             {
457                                 OSL_FAIL( "TheRealValue" );
458                             }
459                             SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
460                             SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
461                             bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
462                             if ( !bParentProp )
463                                 p->aData.pObj->AddFirstRef();
464                         }
465                     }
466                     else
467                         SetError( ERRCODE_BASIC_CONVERSION );
468                     break;
469                 default:
470                     if( p->aData.eType == rVal.eType )
471                         p->aData = rVal;
472                     else
473                     {
474                         SetError( ERRCODE_BASIC_CONVERSION );
475                         if( !p->IsFixed() )
476                             p->aData.eType = SbxNULL;
477                     }
478             }
479             if( !IsError() )
480             {
481                 p->SetModified( true );
482                 p->Broadcast( SfxHintId::BasicDataChanged );
483                 if( eOld != ERRCODE_NONE )
484                     SetError( eOld );
485                 bRes = true;
486             }
487         }
488     }
489     return bRes;
490 }
491 
492 // From 1996-03-28:
493 // Method to execute a pretreatment of the strings at special types.
494 // In particular necessary for BASIC-IDE, so that
495 // the output in the Watch-Window can be written back with PutStringExt,
496 // if Float were declared with ',' as the decimal separator or BOOl
497 // explicit with "TRUE" or "FALSE".
498 // Implementation in ImpConvStringExt (SBXSCAN.CXX)
499 void SbxValue::PutStringExt( const OUString& r )
500 {
501     // Copy; if it is Unicode convert it immediately
502     OUString aStr( r );
503 
504     // Identify the own type (not as in Put() with TheRealValue(),
505     // Objects are not handled anyway)
506     SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
507 
508     // tinker a Source-Value
509     SbxValues aRes(SbxSTRING);
510 
511     // Only if really something was converted, take the copy,
512     // otherwise take the original (Unicode remains)
513     if( ImpConvStringExt( aStr, eTargetType ) )
514         aRes.pOUString = &aStr;
515     else
516         aRes.pOUString = const_cast<OUString*>(&r);
517 
518     // #34939: For Strings which contain a number, and if this has a Num-Type,
519     // set a Fixed flag so that the type will not be changed
520     SbxFlagBits nFlags_ = GetFlags();
521     if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
522         ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
523         eTargetType == SbxBOOL )
524     {
525         SbxValue aVal;
526         aVal.Put( aRes );
527         if( aVal.IsNumeric() )
528             SetFlag( SbxFlagBits::Fixed );
529     }
530 
531     const bool bRet = Put(aRes);
532 
533     // If FIXED resulted in an error, set it back
534     // (UI-Action should not result in an error, but simply fail)
535     if( !bRet )
536         ResetError();
537 
538     SetFlags( nFlags_ );
539 }
540 
541 bool SbxValue::PutBool( bool b )
542 {
543     SbxValues aRes(SbxBOOL);
544     aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
545     return Put(aRes);
546 }
547 
548 bool SbxValue::PutEmpty()
549 {
550     bool bRet = SetType( SbxEMPTY );
551     SetModified( true );
552     return bRet;
553 }
554 
555 void SbxValue::PutNull()
556 {
557     bool bRet = SetType( SbxNULL );
558     if( bRet )
559         SetModified( true );
560 }
561 
562 
563 // Special decimal methods
564 void SbxValue::PutDecimal( css::bridge::oleautomation::Decimal const & rAutomationDec )
565 {
566     SbxValue::Clear();
567     aData.pDecimal = new SbxDecimal( rAutomationDec );
568     aData.pDecimal->addRef();
569     aData.eType = SbxDECIMAL;
570 }
571 
572 void SbxValue::fillAutomationDecimal
573     ( css::bridge::oleautomation::Decimal& rAutomationDec ) const
574 {
575     SbxDecimal* pDecimal = GetDecimal();
576     if( pDecimal != nullptr )
577     {
578         pDecimal->fillAutomationDecimal( rAutomationDec );
579     }
580 }
581 
582 
583 bool SbxValue::PutString( const OUString& r )
584 {
585     SbxValues aRes(SbxSTRING);
586     aRes.pOUString = const_cast<OUString*>(&r);
587     return Put(aRes);
588 }
589 
590 
591 #define PUT( p, e, t, m ) \
592 bool SbxValue::p( t n ) \
593 { SbxValues aRes(e); aRes.m = n; return Put(aRes); }
594 
595 void SbxValue::PutDate( double n )
596 { SbxValues aRes(SbxDATE); aRes.nDouble = n; Put( aRes ); }
597 void SbxValue::PutErr( sal_uInt16 n )
598 { SbxValues aRes(SbxERROR); aRes.nUShort = n; Put( aRes ); }
599 
600 PUT( PutByte,     SbxBYTE,       sal_uInt8,        nByte )
601 PUT( PutChar,     SbxCHAR,       sal_Unicode,      nChar )
602 PUT( PutCurrency, SbxCURRENCY,   sal_Int64,        nInt64 )
603 PUT( PutDouble,   SbxDOUBLE,     double,           nDouble )
604 PUT( PutInteger,  SbxINTEGER,    sal_Int16,        nInteger )
605 PUT( PutLong,     SbxLONG,       sal_Int32,        nLong )
606 PUT( PutObject,   SbxOBJECT,     SbxBase*,         pObj )
607 PUT( PutSingle,   SbxSINGLE,     float,            nSingle )
608 PUT( PutULong,    SbxULONG,      sal_uInt32,       nULong )
609 PUT( PutUShort,   SbxUSHORT,     sal_uInt16,       nUShort )
610 PUT( PutInt64,    SbxSALINT64,   sal_Int64,        nInt64 )
611 PUT( PutUInt64,   SbxSALUINT64,  sal_uInt64,       uInt64 )
612 PUT( PutDecimal,  SbxDECIMAL,    SbxDecimal*,      pDecimal )
613 
614 ////////////////////////// Setting of the data type
615 
616 bool SbxValue::IsFixed() const
617 {
618     return (GetFlags() & SbxFlagBits::Fixed) || ((aData.eType & SbxBYREF) != 0);
619 }
620 
621 // A variable is numeric, if it is EMPTY or really numeric
622 // or if it contains a complete convertible String
623 
624 // #41692, implement it for RTL and Basic-Core separately
625 bool SbxValue::IsNumeric() const
626 {
627     return ImpIsNumeric( /*bOnlyIntntl*/false );
628 }
629 
630 bool SbxValue::IsNumericRTL() const
631 {
632     return ImpIsNumeric( /*bOnlyIntntl*/true );
633 }
634 
635 bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
636 {
637 
638     if( !CanRead() )
639     {
640         SetError( ERRCODE_BASIC_PROP_WRITEONLY );
641         return false;
642     }
643     // Test downcast!!!
644     if( auto pSbxVar = dynamic_cast<const SbxVariable*>( this) )
645         const_cast<SbxVariable*>(pSbxVar)->Broadcast( SfxHintId::BasicDataWanted );
646     SbxDataType t = GetType();
647     if( t == SbxSTRING )
648     {
649         if( aData.pOUString )
650         {
651             OUString s( *aData.pOUString );
652             double n;
653             SbxDataType t2;
654             sal_uInt16 nLen = 0;
655             if( ImpScan( s, n, t2, &nLen, bOnlyIntntl ) == ERRCODE_NONE )
656                 return nLen == s.getLength();
657         }
658         return false;
659     }
660     else
661         return t == SbxEMPTY
662             || ( t >= SbxINTEGER && t <= SbxCURRENCY )
663             || ( t >= SbxCHAR && t <= SbxUINT );
664 }
665 
666 SbxDataType SbxValue::GetType() const
667 {
668     return SbxDataType( aData.eType & 0x0FFF );
669 }
670 
671 
672 bool SbxValue::SetType( SbxDataType t )
673 {
674     DBG_ASSERT( !( t & 0xF000 ), "SetType of BYREF|ARRAY is forbidden!" );
675     if( ( t == SbxEMPTY && aData.eType == SbxVOID )
676      || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
677         return true;
678     if( ( t & 0x0FFF ) == SbxVARIANT )
679     {
680         // Try to set the data type to Variant
681         ResetFlag( SbxFlagBits::Fixed );
682         if( IsFixed() )
683         {
684             SetError( ERRCODE_BASIC_CONVERSION );
685             return false;
686         }
687         t = SbxEMPTY;
688     }
689     if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
690     {
691         if( !CanWrite() || IsFixed() )
692         {
693             SetError( ERRCODE_BASIC_CONVERSION );
694             return false;
695         }
696         else
697         {
698             // De-allocate potential objects
699             switch( aData.eType )
700             {
701                 case SbxSTRING:
702                     delete aData.pOUString;
703                     break;
704                 case SbxOBJECT:
705                     if( aData.pObj && aData.pObj != this )
706                     {
707                         SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
708                         SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
709                         sal_uInt32 nSlotId = pThisVar
710                                     ? pThisVar->GetUserData() & 0xFFFF
711                                     : 0;
712                         DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == "Parent",
713                                     "SID_PARENTOBJECT is not named 'Parent'" );
714                         bool bParentProp = nSlotId == 5345;
715                         if ( !bParentProp )
716                             aData.pObj->ReleaseRef();
717                     }
718                     break;
719                 default: break;
720             }
721             aData.clear(t);
722         }
723     }
724     return true;
725 }
726 
727 bool SbxValue::Convert( SbxDataType eTo )
728 {
729     eTo = SbxDataType( eTo & 0x0FFF );
730     if( ( aData.eType & 0x0FFF ) == eTo )
731         return true;
732     if( !CanWrite() )
733         return false;
734     if( eTo == SbxVARIANT )
735     {
736         // Trial to set the data type to Variant
737         ResetFlag( SbxFlagBits::Fixed );
738         if( IsFixed() )
739         {
740             SetError( ERRCODE_BASIC_CONVERSION );
741             return false;
742         }
743         else
744             return true;
745     }
746     // Converting from null doesn't work. Once null, always null!
747     if( aData.eType == SbxNULL )
748     {
749         SetError( ERRCODE_BASIC_CONVERSION );
750         return false;
751     }
752 
753     // Conversion of the data:
754     SbxValues aNew(eTo);
755     if( Get( aNew ) )
756     {
757         // The data type could be converted. It ends here with fixed elements,
758         // because the data had not to be taken over
759         if( !IsFixed() )
760         {
761             SetType( eTo );
762             Put( aNew );
763             SetModified( true );
764         }
765         return true;
766     }
767     else
768         return false;
769 }
770 ////////////////////////////////// Calculating
771 
772 bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
773 {
774 #if !HAVE_FEATURE_SCRIPTING
775     const bool bVBAInterop = false;
776 #else
777     bool bVBAInterop =  SbiRuntime::isVBAEnabled();
778 #endif
779     SbxDataType eThisType = GetType();
780     SbxDataType eOpType = rOp.GetType();
781     ErrCode eOld = GetError();
782     if( eOld != ERRCODE_NONE )
783         ResetError();
784     if( !CanWrite() )
785         SetError( ERRCODE_BASIC_PROP_READONLY );
786     else if( !rOp.CanRead() )
787         SetError( ERRCODE_BASIC_PROP_WRITEONLY );
788     // Special rule 1: If one operand is null, the result is null
789     else if( eThisType == SbxNULL || eOpType == SbxNULL )
790         SetType( SbxNULL );
791     else
792     {
793         SbxValues aL, aR;
794         bool bDecimal = false;
795         if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
796              ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
797              ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
798         {
799             goto Lbl_OpIsDouble;
800         }
801         else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && (  eOp == SbxPLUS ) ) )
802         {
803             if( eOp == SbxCAT || eOp == SbxPLUS )
804             {
805                 // From 1999-11-5, keep OUString in mind
806                 aL.eType = aR.eType = SbxSTRING;
807                 rOp.Get( aR );
808                 // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
809                 if( rOp.GetType() == SbxEMPTY )
810                     goto Lbl_OpIsEmpty;     // concatenate empty, *this stays lhs as result
811                 Get( aL );
812 
813                 // #30576: To begin with test, if the conversion worked
814                 if( aL.pOUString != nullptr && aR.pOUString != nullptr )
815                 {
816                     // tdf#108039: catch possible bad_alloc
817                     try {
818                         *aL.pOUString += *aR.pOUString;
819                     }
820                     catch (const std::bad_alloc&) {
821                         SetError(ERRCODE_BASIC_MATH_OVERFLOW);
822                     }
823                 }
824                 // Not even Left OK?
825                 else if( aL.pOUString == nullptr )
826                 {
827                     aL.pOUString = new OUString();
828                 }
829             }
830             else
831                 SetError( ERRCODE_BASIC_CONVERSION );
832         }
833         else if( eOpType == SbxSTRING && rOp.IsFixed() )
834         {   // Numeric: there is no String allowed on the right side
835             SetError( ERRCODE_BASIC_CONVERSION );
836             // falls all the way out
837         }
838         else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
839         {
840             if( GetType() == eOpType )
841             {
842                 if( GetType() == SbxSALUINT64 || GetType() == SbxSALINT64
843                  || GetType() == SbxCURRENCY  || GetType() == SbxULONG )
844                     aL.eType = aR.eType = GetType();
845                 else if ( bVBAInterop && eOpType == SbxBOOL )
846                     aL.eType = aR.eType = SbxBOOL;
847                 else
848                     aL.eType = aR.eType = SbxLONG;
849             }
850             else
851                 aL.eType = aR.eType = SbxLONG;
852 
853             if( rOp.Get( aR ) )     // re-do Get after type assigns above
854             {
855                 if( Get( aL ) ) switch( eOp )
856                 {
857                     /* TODO: For SbxEMPTY operands with boolean operators use
858                      * the VBA Nothing definition of Comparing Nullable Types?
859                      * https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/nullable-value-types
860                      */
861                     /* TODO: it is unclear yet whether this also should be done
862                      * for the non-bVBAInterop case or not, or at all, consider
863                      * user defined spreadsheet functions where an empty cell
864                      * is SbxEMPTY and usually is treated as 0 zero or "" empty
865                      * string.
866                      */
867                     case SbxIDIV:
868                         if( aL.eType == SbxCURRENCY )
869                             if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
870                             else {
871                                 aL.nInt64 /= aR.nInt64;
872                                 aL.nInt64 *= CURRENCY_FACTOR;
873                         }
874                         else if( aL.eType == SbxSALUINT64 )
875                             if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
876                             else aL.uInt64 /= aR.uInt64;
877                         else if( aL.eType == SbxSALINT64 )
878                             if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
879                             else aL.nInt64 /= aR.nInt64;
880                         else if( aL.eType == SbxLONG )
881                             if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
882                             else aL.nLong /= aR.nLong;
883                         else
884                             if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
885                             else aL.nULong /= aR.nULong;
886                         break;
887                     case SbxMOD:
888                         if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
889                             if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
890                             else aL.nInt64 %= aR.nInt64;
891                         else if( aL.eType == SbxSALUINT64 )
892                             if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
893                             else aL.uInt64 %= aR.uInt64;
894                         else if( aL.eType == SbxLONG )
895                             if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
896                             else aL.nLong %= aR.nLong;
897                         else
898                             if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
899                             else aL.nULong %= aR.nULong;
900                         break;
901                     case SbxAND:
902                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
903                             aL.nInt64 &= aR.nInt64;
904                         else
905                             aL.nLong &= aR.nLong;
906                         break;
907                     case SbxOR:
908                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
909                             aL.nInt64 |= aR.nInt64;
910                         else
911                             aL.nLong |= aR.nLong;
912                         break;
913                     case SbxXOR:
914                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
915                             aL.nInt64 ^= aR.nInt64;
916                         else
917                             aL.nLong ^= aR.nLong;
918                         break;
919                     case SbxEQV:
920                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
921                             aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
922                         else
923                             aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
924                         break;
925                     case SbxIMP:
926                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
927                             aL.nInt64 = ~aL.nInt64 | aR.nInt64;
928                         else
929                             aL.nLong = ~aL.nLong | aR.nLong;
930                         break;
931                     case SbxNOT:
932                         if( aL.eType != SbxLONG && aL.eType != SbxULONG )
933                         {
934                             if ( aL.eType != SbxBOOL )
935                                 aL.nInt64 = ~aL.nInt64;
936                             else
937                                 aL.nLong = ~aL.nLong;
938                         }
939                         else
940                             aL.nLong = ~aL.nLong;
941                         break;
942                     default: break;
943                 }
944             }
945         }
946         else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
947               && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
948         {
949             aL.eType = aR.eType = SbxDECIMAL;
950             bDecimal = true;
951             if( rOp.Get( aR ) && Get( aL ) )
952             {
953                 if( aL.pDecimal && aR.pDecimal )
954                 {
955                     bool bOk = true;
956                     switch( eOp )
957                     {
958                         case SbxMUL:
959                             bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
960                             break;
961                         case SbxDIV:
962                             if( aR.pDecimal->isZero() )
963                                 SetError( ERRCODE_BASIC_ZERODIV );
964                             else
965                                 bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
966                             break;
967                         case SbxPLUS:
968                             bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
969                             break;
970                         case SbxMINUS:
971                             bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
972                             break;
973                         case SbxNEG:
974                             bOk = ( aL.pDecimal->neg() );
975                             break;
976                         default:
977                             SetError( ERRCODE_BASIC_BAD_ARGUMENT );
978                     }
979                     if( !bOk )
980                         SetError( ERRCODE_BASIC_MATH_OVERFLOW );
981                 }
982                 else
983                 {
984                     SetError( ERRCODE_BASIC_CONVERSION );
985                 }
986             }
987         }
988         else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
989         {
990             aL.eType = SbxCURRENCY;
991             aR.eType = SbxCURRENCY;
992 
993             if( rOp.Get( aR ) )
994             {
995                 if( Get( aL ) ) switch( eOp )
996                 {
997                     case SbxMUL:
998                         {
999                             // first overflow check: see if product will fit - test real value of product (hence 2 curr factors)
1000                             double dTest = static_cast<double>(aL.nInt64) * static_cast<double>(aR.nInt64) / double(CURRENCY_FACTOR_SQUARE);
1001                             if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1002                             {
1003                                 aL.nInt64 = SAL_MAX_INT64;
1004                                 if( dTest < SbxMINCURR ) aL.nInt64 = SAL_MIN_INT64;
1005                                 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1006                                 break;
1007                             }
1008                             // second overflow check: see if unscaled product overflows - if so use doubles
1009                             dTest = static_cast<double>(aL.nInt64) * static_cast<double>(aR.nInt64);
1010                             if( !(o3tl::convertsToAtLeast(dTest, SAL_MIN_INT64)
1011                                   && o3tl::convertsToAtMost(dTest, SAL_MAX_INT64)))
1012                             {
1013                                 aL.nInt64 = static_cast<sal_Int64>( dTest / double(CURRENCY_FACTOR) );
1014                                 break;
1015                             }
1016                             // precise calc: multiply then scale back (move decimal pt)
1017                             aL.nInt64 *= aR.nInt64;
1018                             aL.nInt64 /= CURRENCY_FACTOR;
1019                             break;
1020                         }
1021 
1022                     case SbxDIV:
1023                         {
1024                             if( !aR.nInt64 )
1025                             {
1026                                 SetError( ERRCODE_BASIC_ZERODIV );
1027                                 break;
1028                             }
1029                             // first overflow check: see if quotient will fit - calc real value of quotient (curr factors cancel)
1030                             double dTest = static_cast<double>(aL.nInt64) / static_cast<double>(aR.nInt64);
1031                             if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1032                             {
1033                                 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1034                                 break;
1035                             }
1036                             // second overflow check: see if scaled dividend overflows - if so use doubles
1037                             dTest = static_cast<double>(aL.nInt64) * double(CURRENCY_FACTOR);
1038                             if( !(o3tl::convertsToAtLeast(dTest, SAL_MIN_INT64)
1039                                   && o3tl::convertsToAtMost(dTest, SAL_MAX_INT64)))
1040                             {
1041                                 aL.nInt64 = static_cast<sal_Int64>(dTest / static_cast<double>(aR.nInt64));
1042                                 break;
1043                             }
1044                             // precise calc: scale (move decimal pt) then divide
1045                             aL.nInt64 *= CURRENCY_FACTOR;
1046                             aL.nInt64 /= aR.nInt64;
1047                             break;
1048                         }
1049 
1050                     case SbxPLUS:
1051                         {
1052                             double dTest = ( static_cast<double>(aL.nInt64) + static_cast<double>(aR.nInt64) ) / double(CURRENCY_FACTOR);
1053                             if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1054                             {
1055                                 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1056                                 break;
1057                             }
1058                             aL.nInt64 += aR.nInt64;
1059                             break;
1060                         }
1061 
1062                     case SbxMINUS:
1063                         {
1064                             double dTest = ( static_cast<double>(aL.nInt64) - static_cast<double>(aR.nInt64) ) / double(CURRENCY_FACTOR);
1065                             if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1066                             {
1067                                 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1068                                 break;
1069                             }
1070                             aL.nInt64 -= aR.nInt64;
1071                             break;
1072                         }
1073                     case SbxNEG:
1074                         aL.nInt64 = -aL.nInt64;
1075                         break;
1076                     default:
1077                         SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1078                 }
1079             }
1080         }
1081         else
1082 Lbl_OpIsDouble:
1083         {   // other types and operators including Date, Double and Single
1084             aL.eType = aR.eType = SbxDOUBLE;
1085             if( rOp.Get( aR ) )
1086             {
1087                 if( Get( aL ) )
1088                 {
1089                     switch( eOp )
1090                     {
1091                         case SbxEXP:
1092                             aL.nDouble = pow( aL.nDouble, aR.nDouble );
1093                             break;
1094                         case SbxMUL:
1095                             aL.nDouble *= aR.nDouble; break;
1096                         case SbxDIV:
1097                             if( !aR.nDouble ) SetError( ERRCODE_BASIC_ZERODIV );
1098                             else aL.nDouble /= aR.nDouble;
1099                             break;
1100                         case SbxPLUS:
1101                             aL.nDouble += aR.nDouble; break;
1102                         case SbxMINUS:
1103                             aL.nDouble -= aR.nDouble; break;
1104                         case SbxNEG:
1105                             aL.nDouble = -aL.nDouble; break;
1106                         default:
1107                             SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1108                     }
1109                     // Date with "+" or "-" needs special handling that
1110                     // forces the Date type. If the operation is '+' the
1111                     // result is always a Date, if '-' the result is only
1112                     // a Date if one of lhs or rhs ( but not both ) is already
1113                     // a Date
1114                     if( GetType() == SbxDATE || rOp.GetType() == SbxDATE )
1115                     {
1116                         if( eOp == SbxPLUS  || ( ( eOp == SbxMINUS ) &&  ( GetType() != rOp.GetType() ) ) )
1117                             aL.eType = SbxDATE;
1118                     }
1119 
1120                 }
1121             }
1122 
1123         }
1124         if( !IsError() )
1125             Put( aL );
1126         if( bDecimal )
1127         {
1128             releaseDecimalPtr( aL.pDecimal );
1129             releaseDecimalPtr( aR.pDecimal );
1130         }
1131     }
1132 Lbl_OpIsEmpty:
1133 
1134     bool bRes = !IsError();
1135     if( bRes && eOld != ERRCODE_NONE )
1136         SetError( eOld );
1137     return bRes;
1138 }
1139 
1140 // The comparison routine deliver TRUE or FALSE.
1141 
1142 bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1143 {
1144 #if !HAVE_FEATURE_SCRIPTING
1145     const bool bVBAInterop = false;
1146 #else
1147     bool bVBAInterop =  SbiRuntime::isVBAEnabled();
1148 #endif
1149 
1150     bool bRes = false;
1151     ErrCode eOld = GetError();
1152     if( eOld != ERRCODE_NONE )
1153         ResetError();
1154     if( !CanRead() || !rOp.CanRead() )
1155         SetError( ERRCODE_BASIC_PROP_WRITEONLY );
1156     else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1157     {
1158         bRes = true;
1159     }
1160     else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1161         bRes = !bVBAInterop || ( eOp == SbxEQ );
1162     // Special rule 1: If an operand is null, the result is FALSE
1163     else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1164         bRes = false;
1165     // Special rule 2: If both are variant and one is numeric
1166     // and the other is a String, num is < str
1167     else if( !IsFixed() && !rOp.IsFixed()
1168      && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1169     )
1170         bRes = eOp == SbxLT || eOp == SbxLE || eOp == SbxNE;
1171     else if( !IsFixed() && !rOp.IsFixed()
1172      && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1173 && !bVBAInterop
1174     )
1175         bRes = eOp == SbxGT || eOp == SbxGE || eOp == SbxNE;
1176     else
1177     {
1178         SbxValues aL, aR;
1179         // If one of the operands is a String,
1180         // a String comparing take place
1181         if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1182         {
1183             aL.eType = aR.eType = SbxSTRING;
1184             if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
1185             {
1186                 case SbxEQ:
1187                     bRes = ( *aL.pOUString == *aR.pOUString ); break;
1188                 case SbxNE:
1189                     bRes = ( *aL.pOUString != *aR.pOUString ); break;
1190                 case SbxLT:
1191                     bRes = ( *aL.pOUString <  *aR.pOUString ); break;
1192                 case SbxGT:
1193                     bRes = ( *aL.pOUString >  *aR.pOUString ); break;
1194                 case SbxLE:
1195                     bRes = ( *aL.pOUString <= *aR.pOUString ); break;
1196                 case SbxGE:
1197                     bRes = ( *aL.pOUString >= *aR.pOUString ); break;
1198                 default:
1199                     SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1200             }
1201         }
1202         // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1203         //              otherwise it shows a numeric error
1204         else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1205         {
1206             aL.eType = aR.eType = SbxSINGLE;
1207             if( Get( aL ) && rOp.Get( aR ) )
1208               switch( eOp )
1209             {
1210                 case SbxEQ:
1211                     bRes = ( aL.nSingle == aR.nSingle ); break;
1212                 case SbxNE:
1213                     bRes = ( aL.nSingle != aR.nSingle ); break;
1214                 case SbxLT:
1215                     bRes = ( aL.nSingle <  aR.nSingle ); break;
1216                 case SbxGT:
1217                     bRes = ( aL.nSingle >  aR.nSingle ); break;
1218                 case SbxLE:
1219                     bRes = ( aL.nSingle <= aR.nSingle ); break;
1220                 case SbxGE:
1221                     bRes = ( aL.nSingle >= aR.nSingle ); break;
1222                 default:
1223                     SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1224             }
1225         }
1226         else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1227         {
1228             aL.eType = aR.eType = SbxDECIMAL;
1229             Get( aL );
1230             rOp.Get( aR );
1231             if( aL.pDecimal && aR.pDecimal )
1232             {
1233                 SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1234                 switch( eOp )
1235                 {
1236                     case SbxEQ:
1237                         bRes = ( eRes == SbxDecimal::CmpResult::EQ ); break;
1238                     case SbxNE:
1239                         bRes = ( eRes != SbxDecimal::CmpResult::EQ ); break;
1240                     case SbxLT:
1241                         bRes = ( eRes == SbxDecimal::CmpResult::LT ); break;
1242                     case SbxGT:
1243                         bRes = ( eRes == SbxDecimal::CmpResult::GT ); break;
1244                     case SbxLE:
1245                         bRes = ( eRes != SbxDecimal::CmpResult::GT ); break;
1246                     case SbxGE:
1247                         bRes = ( eRes != SbxDecimal::CmpResult::LT ); break;
1248                     default:
1249                         SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1250                 }
1251             }
1252             else
1253             {
1254                 SetError( ERRCODE_BASIC_CONVERSION );
1255             }
1256             releaseDecimalPtr( aL.pDecimal );
1257             releaseDecimalPtr( aR.pDecimal );
1258         }
1259         // Everything else comparing on a SbxDOUBLE-Basis
1260         else
1261         {
1262             aL.eType = aR.eType = SbxDOUBLE;
1263             bool bGetL = Get( aL );
1264             bool bGetR = rOp.Get( aR );
1265             if( bGetL && bGetR )
1266               switch( eOp )
1267             {
1268                 case SbxEQ:
1269                     bRes = ( aL.nDouble == aR.nDouble ); break;
1270                 case SbxNE:
1271                     bRes = ( aL.nDouble != aR.nDouble ); break;
1272                 case SbxLT:
1273                     bRes = ( aL.nDouble <  aR.nDouble ); break;
1274                 case SbxGT:
1275                     bRes = ( aL.nDouble >  aR.nDouble ); break;
1276                 case SbxLE:
1277                     bRes = ( aL.nDouble <= aR.nDouble ); break;
1278                 case SbxGE:
1279                     bRes = ( aL.nDouble >= aR.nDouble ); break;
1280                 default:
1281                     SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1282             }
1283             // at least one value was got
1284             // if this is VBA then a conversion error for one
1285             // side will yield a false result of an equality test
1286             else if ( bGetR || bGetL )
1287             {
1288                 if ( bVBAInterop && eOp == SbxEQ && GetError() == ERRCODE_BASIC_CONVERSION )
1289                 {
1290 #ifndef IOS
1291                     ResetError();
1292                     bRes = false;
1293 #endif
1294                 }
1295             }
1296         }
1297     }
1298     if( eOld != ERRCODE_NONE )
1299         SetError( eOld );
1300     return bRes;
1301 }
1302 
1303 ///////////////////////////// Reading/Writing
1304 
1305 bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1306 {
1307     // #TODO see if these types are really dumped to any stream
1308     // more than likely this is functionality used in the binfilter alone
1309     SbxValue::Clear();
1310     sal_uInt16 nType;
1311     r.ReadUInt16( nType );
1312     aData.eType = SbxDataType( nType );
1313     switch( nType )
1314     {
1315         case SbxBOOL:
1316         case SbxINTEGER:
1317             r.ReadInt16( aData.nInteger ); break;
1318         case SbxLONG:
1319             r.ReadInt32( aData.nLong ); break;
1320         case SbxSINGLE:
1321         {
1322             // Floats as ASCII
1323             OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1324                 RTL_TEXTENCODING_ASCII_US);
1325             double d;
1326             SbxDataType t;
1327             if( ImpScan( aVal, d, t, nullptr, true ) != ERRCODE_NONE || t == SbxDOUBLE )
1328             {
1329                 aData.nSingle = 0.0F;
1330                 return false;
1331             }
1332             aData.nSingle = static_cast<float>(d);
1333             break;
1334         }
1335         case SbxDATE:
1336         case SbxDOUBLE:
1337         {
1338             // Floats as ASCII
1339             OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1340                 RTL_TEXTENCODING_ASCII_US);
1341             SbxDataType t;
1342             if( ImpScan( aVal, aData.nDouble, t, nullptr, true ) != ERRCODE_NONE )
1343             {
1344                 aData.nDouble = 0.0;
1345                 return false;
1346             }
1347             break;
1348         }
1349         case SbxSALINT64:
1350             r.ReadInt64(aData.nInt64);
1351             break;
1352         case SbxSALUINT64:
1353             r.ReadUInt64( aData.uInt64 );
1354             break;
1355         case SbxCURRENCY:
1356         {
1357             sal_uInt32 tmpHi = 0;
1358             sal_uInt32 tmpLo = 0;
1359             r.ReadUInt32( tmpHi ).ReadUInt32( tmpLo );
1360             aData.nInt64 = (static_cast<sal_Int64>(tmpHi) << 32);
1361             aData.nInt64 |= static_cast<sal_Int64>(tmpLo);
1362             break;
1363         }
1364         case SbxSTRING:
1365         {
1366             OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1367                 RTL_TEXTENCODING_ASCII_US);
1368             if( !aVal.isEmpty() )
1369                 aData.pOUString = new OUString( aVal );
1370             else
1371                 aData.pOUString = nullptr; // JSM 1995-09-22
1372             break;
1373         }
1374         case SbxERROR:
1375         case SbxUSHORT:
1376             r.ReadUInt16( aData.nUShort ); break;
1377         case SbxOBJECT:
1378         {
1379             sal_uInt8 nMode;
1380             r.ReadUChar( nMode );
1381             switch( nMode )
1382             {
1383                 case 0:
1384                     aData.pObj = nullptr;
1385                     break;
1386                 case 1:
1387                 {
1388                     auto ref = SbxBase::Load( r );
1389                     aData.pObj = ref.get();
1390                     // if necessary increment Ref-Count
1391                     if (aData.pObj)
1392                         aData.pObj->AddFirstRef();
1393                     return ( aData.pObj != nullptr );
1394                 }
1395                 case 2:
1396                     aData.pObj = this;
1397                     break;
1398             }
1399             break;
1400         }
1401         case SbxCHAR:
1402         {
1403             char c;
1404             r.ReadChar( c );
1405             aData.nChar = c;
1406             break;
1407         }
1408         case SbxBYTE:
1409             r.ReadUChar( aData.nByte ); break;
1410         case SbxULONG:
1411             r.ReadUInt32( aData.nULong ); break;
1412         case SbxINT:
1413         {
1414             sal_uInt8 n;
1415             r.ReadUChar( n );
1416             // Match the Int on this system?
1417             if( n > SAL_TYPES_SIZEOFINT )
1418             {
1419                 r.ReadInt32( aData.nLong );
1420                 aData.eType = SbxLONG;
1421             }
1422             else {
1423                 sal_Int32 nInt;
1424                 r.ReadInt32( nInt );
1425                 aData.nInt = nInt;
1426             }
1427             break;
1428         }
1429         case SbxUINT:
1430         {
1431             sal_uInt8 n;
1432             r.ReadUChar( n );
1433             // Match the UInt on this system?
1434             if( n > SAL_TYPES_SIZEOFINT )
1435             {
1436                 r.ReadUInt32( aData.nULong );
1437                 aData.eType = SbxULONG;
1438             }
1439             else {
1440                 sal_uInt32 nUInt;
1441                 r.ReadUInt32( nUInt );
1442                 aData.nUInt = nUInt;
1443             }
1444             break;
1445         }
1446         case SbxEMPTY:
1447         case SbxNULL:
1448         case SbxVOID:
1449             break;
1450         case SbxDATAOBJECT:
1451             r.ReadInt32( aData.nLong );
1452             break;
1453         // #78919 For backwards compatibility
1454         case SbxWSTRING:
1455         case SbxWCHAR:
1456             break;
1457         default:
1458             aData.clear(SbxNULL);
1459             ResetFlag(SbxFlagBits::Fixed);
1460             SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
1461 
1462             return false;
1463     }
1464     return true;
1465 }
1466 
1467     bool SbxValue::StoreData( SvStream& r ) const
1468     {
1469         sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1470         r.WriteUInt16( nType );
1471         switch( nType & 0x0FFF )
1472         {
1473             case SbxBOOL:
1474             case SbxINTEGER:
1475                 r.WriteInt16( aData.nInteger ); break;
1476             case SbxLONG:
1477                 r.WriteInt32( aData.nLong ); break;
1478             case SbxDATE:
1479                 // #49935: Save as double, otherwise an error during the read in
1480                 const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>( ( nType & 0xF000 ) | SbxDOUBLE );
1481                 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1482                 const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>(nType);
1483                 break;
1484             case SbxSINGLE:
1485             case SbxDOUBLE:
1486                 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1487                 break;
1488             case SbxSALUINT64:
1489             case SbxSALINT64:
1490                 // see comment in SbxValue::StoreData
1491                 r.WriteUInt64( aData.uInt64 );
1492                 break;
1493             case SbxCURRENCY:
1494             {
1495                 sal_Int32 tmpHi = ( (aData.nInt64 >> 32) &  0xFFFFFFFF );
1496                 sal_Int32 tmpLo = static_cast<sal_Int32>(aData.nInt64);
1497                 r.WriteInt32( tmpHi ).WriteInt32( tmpLo );
1498                 break;
1499             }
1500             case SbxSTRING:
1501                 if( aData.pOUString )
1502                 {
1503                     write_uInt16_lenPrefixed_uInt8s_FromOUString(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1504                 }
1505                 else
1506                 {
1507                     write_uInt16_lenPrefixed_uInt8s_FromOUString(r, std::u16string_view(), RTL_TEXTENCODING_ASCII_US);
1508             }
1509             break;
1510             case SbxERROR:
1511             case SbxUSHORT:
1512                 r.WriteUInt16( aData.nUShort ); break;
1513             case SbxOBJECT:
1514                 // to save itself as Objectptr does not work!
1515                 if( aData.pObj )
1516                 {
1517                     if( dynamic_cast<SbxValue*>( aData.pObj) != this  )
1518                     {
1519                         r.WriteUChar( 1 );
1520                         return aData.pObj->Store( r );
1521                     }
1522                     else
1523                         r.WriteUChar( 2 );
1524                 }
1525                 else
1526                     r.WriteUChar( 0 );
1527                 break;
1528             case SbxCHAR:
1529             {
1530                 char c = sal::static_int_cast< char >(aData.nChar);
1531                 r.WriteChar( c );
1532                 break;
1533             }
1534             case SbxBYTE:
1535                 r.WriteUChar( aData.nByte ); break;
1536             case SbxULONG:
1537                 r.WriteUInt32( aData.nULong ); break;
1538             case SbxINT:
1539             {
1540                 r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteInt32( aData.nInt );
1541                 break;
1542             }
1543             case SbxUINT:
1544             {
1545                 r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteUInt32( aData.nUInt );
1546                 break;
1547             }
1548             case SbxEMPTY:
1549             case SbxNULL:
1550             case SbxVOID:
1551                 break;
1552             case SbxDATAOBJECT:
1553                 r.WriteInt32( aData.nLong );
1554                 break;
1555             // #78919 For backwards compatibility
1556             case SbxWSTRING:
1557             case SbxWCHAR:
1558                 break;
1559             default:
1560                 SAL_WARN( "basic.sbx", "Saving a non-supported data type" );
1561                 return false;
1562         }
1563         return true;
1564     }
1565 
1566 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1567