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