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