Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / sbx / sbxvalue.cxx
blobc32d51f31b429813e3157e376e0ae29d11609c9a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <math.h>
24 #include <o3tl/float_int_conversion.hxx>
25 #include <tools/debug.hxx>
26 #include <tools/stream.hxx>
27 #include <sal/log.hxx>
29 #include <basic/sbx.hxx>
30 #include <sbunoobj.hxx>
31 #include "sbxconv.hxx"
32 #include <runtime.hxx>
35 ///////////////////////////// constructors
37 SbxValue::SbxValue() : SbxBase()
39 aData.eType = SbxEMPTY;
42 SbxValue::SbxValue( SbxDataType t ) : SbxBase()
44 int n = t & 0x0FFF;
46 if( n == SbxVARIANT )
47 n = SbxEMPTY;
48 else
49 SetFlag( SbxFlagBits::Fixed );
50 aData.clear(SbxDataType( n ));
53 SbxValue::SbxValue( const SbxValue& r )
54 : SvRefBase( r ), SbxBase( r )
56 if( !r.CanRead() )
58 SetError( ERRCODE_BASIC_PROP_WRITEONLY );
59 if( !IsFixed() )
60 aData.eType = SbxNULL;
62 else
64 const_cast<SbxValue*>(&r)->Broadcast( SfxHintId::BasicDataWanted );
65 aData = r.aData;
66 // Copy pointer, increment references
67 switch( aData.eType )
69 case SbxSTRING:
70 if( aData.pOUString )
71 aData.pOUString = new OUString( *aData.pOUString );
72 break;
73 case SbxOBJECT:
74 if( aData.pObj )
75 aData.pObj->AddFirstRef();
76 break;
77 case SbxDECIMAL:
78 if( aData.pDecimal )
79 aData.pDecimal->addRef();
80 break;
81 default: break;
86 SbxValue& SbxValue::operator=( const SbxValue& r )
88 if( &r != this )
90 if( !CanWrite() )
91 SetError( ERRCODE_BASIC_PROP_READONLY );
92 else
94 // string -> byte array
95 if( IsFixed() && (aData.eType == SbxOBJECT)
96 && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
97 && (r.aData.eType == SbxSTRING) )
99 OUString aStr = r.GetOUString();
100 SbxArray* pArr = StringToByteArray(aStr);
101 PutObject(pArr);
102 return *this;
104 // byte array -> string
105 if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
106 && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
107 && (aData.eType == SbxSTRING) )
109 SbxBase* pObj = r.GetObject();
110 SbxArray* pArr = dynamic_cast<SbxArray*>( pObj );
111 if( pArr )
113 OUString aStr = ByteArrayToString( pArr );
114 PutString(aStr);
115 return *this;
118 // Readout the content of the variables
119 SbxValues aNew;
120 if( IsFixed() )
121 // then the type has to match
122 aNew.eType = aData.eType;
123 else if( r.IsFixed() )
124 // Source fixed: copy the type
125 aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
126 else
127 // both variant: then don't care
128 aNew.eType = SbxVARIANT;
129 if( r.Get( aNew ) )
130 Put( aNew );
133 return *this;
136 SbxValue::~SbxValue()
138 SetFlag( SbxFlagBits::Write );
139 SbxValue::Clear();
142 void SbxValue::Clear()
144 switch( aData.eType )
146 case SbxNULL:
147 case SbxEMPTY:
148 case SbxVOID:
149 break;
150 case SbxSTRING:
151 delete aData.pOUString; aData.pOUString = nullptr;
152 break;
153 case SbxOBJECT:
154 if( aData.pObj )
156 if( aData.pObj != this )
158 SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
159 SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
160 bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
161 if ( !bParentProp )
162 aData.pObj->ReleaseRef();
164 aData.pObj = nullptr;
166 break;
167 case SbxDECIMAL:
168 releaseDecimalPtr( aData.pDecimal );
169 break;
170 case SbxDATAOBJECT:
171 aData.pData = nullptr; break;
172 default:
174 SbxValues aEmpty;
175 aEmpty.clear(GetType());
176 Put( aEmpty );
181 // Dummy
183 void SbxValue::Broadcast( SfxHintId )
186 //////////////////////////// Readout data
188 // Detect the "right" variables. If it is an object, will be addressed either
189 // the object itself or its default property.
190 // If the variable contain a variable or an object, this will be
191 // addressed.
193 SbxValue* SbxValue::TheRealValue( bool bObjInObjError ) const
195 SbxValue* p = const_cast<SbxValue*>(this);
196 for( ;; )
198 SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
199 if( t == SbxOBJECT )
201 // The block contains an object or a variable
202 SbxObject* pObj = dynamic_cast<SbxObject*>( p->aData.pObj );
203 if( pObj )
205 // Has the object a default property?
206 SbxVariable* pDflt = pObj->GetDfltProperty();
208 // If this is an object and contains itself,
209 // we cannot access on it
210 // The old condition to set an error is not correct,
211 // because e.g. a regular variant variable with an object
212 // could be affected if another value should be assigned.
213 // Therefore with flag.
214 if( bObjInObjError && !pDflt &&
215 static_cast<SbxValue*>(pObj)->aData.eType == SbxOBJECT &&
216 static_cast<SbxValue*>(pObj)->aData.pObj == pObj )
218 #if !HAVE_FEATURE_SCRIPTING
219 const bool bSuccess = false;
220 #else
221 bool bSuccess = handleToStringForCOMObjects( pObj, p );
222 #endif
223 if( !bSuccess )
225 SetError( ERRCODE_BASIC_BAD_PROP_VALUE );
226 p = nullptr;
229 else if( pDflt )
230 p = pDflt;
231 break;
233 // Did we have an array?
234 SbxArray* pArray = dynamic_cast<SbxArray*>( p->aData.pObj );
235 if( pArray )
237 // When indicated get the parameter
238 SbxArray* pPar = nullptr;
239 SbxVariable* pVar = dynamic_cast<SbxVariable*>( p );
240 if( pVar )
241 pPar = pVar->GetParameters();
242 if( pPar )
244 // Did we have a dimensioned array?
245 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( p->aData.pObj );
246 if( pDimArray )
247 p = pDimArray->Get( pPar );
248 else
249 p = pArray->Get( pPar->Get( 1 )->GetInteger() );
250 break;
253 // Otherwise guess a SbxValue
254 SbxValue* pVal = dynamic_cast<SbxValue*>( p->aData.pObj );
255 if( pVal )
256 p = pVal;
257 else
258 break;
260 else
261 break;
263 return p;
266 bool SbxValue::Get( SbxValues& rRes ) const
268 bool bRes = false;
269 ErrCode eOld = GetError();
270 if( eOld != ERRCODE_NONE )
271 ResetError();
272 if( !CanRead() )
274 SetError( ERRCODE_BASIC_PROP_WRITEONLY );
275 rRes.pObj = nullptr;
277 else
279 // If an object or a VARIANT is requested, don't search the real values
280 SbxValue* p = const_cast<SbxValue*>(this);
281 if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
282 p = TheRealValue( true );
283 if( p )
285 p->Broadcast( SfxHintId::BasicDataWanted );
286 switch( rRes.eType )
288 case SbxEMPTY:
289 case SbxVOID:
290 case SbxNULL: break;
291 case SbxVARIANT: rRes = p->aData; break;
292 case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
293 case SbxLONG: rRes.nLong = ImpGetLong( &p->aData ); break;
294 case SbxSALINT64: rRes.nInt64 = ImpGetInt64( &p->aData ); break;
295 case SbxSALUINT64: rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
296 case SbxSINGLE: rRes.nSingle = ImpGetSingle( &p->aData ); break;
297 case SbxDOUBLE: rRes.nDouble = ImpGetDouble( &p->aData ); break;
298 case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
299 case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
300 case SbxDATE: rRes.nDouble = ImpGetDate( &p->aData ); break;
301 case SbxBOOL:
302 rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
303 ImpGetBool( &p->aData ) );
304 break;
305 case SbxCHAR: rRes.nChar = ImpGetChar( &p->aData ); break;
306 case SbxBYTE: rRes.nByte = ImpGetByte( &p->aData ); break;
307 case SbxUSHORT: rRes.nUShort = ImpGetUShort( &p->aData ); break;
308 case SbxULONG: rRes.nULong = ImpGetULong( &p->aData ); break;
309 case SbxLPSTR:
310 case SbxSTRING: p->aPic = ImpGetString( &p->aData );
311 rRes.pOUString = &p->aPic; break;
312 case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
313 rRes.pOUString = &p->aPic; break;
314 case SbxINT:
315 rRes.nInt = static_cast<int>(ImpGetLong( &p->aData ));
316 break;
317 case SbxUINT:
318 rRes.nUInt = static_cast<int>(ImpGetULong( &p->aData ));
319 break;
320 case SbxOBJECT:
321 if( p->aData.eType == SbxOBJECT )
322 rRes.pObj = p->aData.pObj;
323 else
325 SetError( ERRCODE_BASIC_NO_OBJECT );
326 rRes.pObj = nullptr;
328 break;
329 default:
330 if( p->aData.eType == rRes.eType )
331 rRes = p->aData;
332 else
334 SetError( ERRCODE_BASIC_CONVERSION );
335 rRes.pObj = nullptr;
339 else
341 // Object contained itself
342 SbxDataType eTemp = rRes.eType;
343 rRes.clear(eTemp);
346 if( !IsError() )
348 bRes = true;
349 if( eOld != ERRCODE_NONE )
350 SetError( eOld );
352 return bRes;
355 const OUString& SbxValue::GetCoreString() const
357 SbxValues aRes;
358 aRes.eType = SbxCoreSTRING;
359 if( Get( aRes ) )
361 const_cast<SbxValue*>(this)->aToolString = *aRes.pOUString;
363 else
365 const_cast<SbxValue*>(this)->aToolString.clear();
367 return aToolString;
370 OUString SbxValue::GetOUString() const
372 OUString aResult;
373 SbxValues aRes;
374 aRes.eType = SbxSTRING;
375 if( Get( aRes ) )
377 aResult = *aRes.pOUString;
379 return aResult;
382 bool SbxValue::GetBool() const
384 SbxValues aRes;
385 aRes.eType = SbxBOOL;
386 Get( aRes );
387 return aRes.nUShort != 0;
390 #define GET( g, e, t, m ) \
391 t SbxValue::g() const { SbxValues aRes(e); Get( aRes ); return aRes.m; }
393 GET( GetByte, SbxBYTE, sal_uInt8, nByte )
394 GET( GetChar, SbxCHAR, sal_Unicode, nChar )
395 GET( GetCurrency, SbxCURRENCY, sal_Int64, nInt64 )
396 GET( GetDate, SbxDATE, double, nDouble )
397 GET( GetDouble, SbxDOUBLE, double, nDouble )
398 GET( GetInteger, SbxINTEGER, sal_Int16, nInteger )
399 GET( GetLong, SbxLONG, sal_Int32, nLong )
400 GET( GetObject, SbxOBJECT, SbxBase*, pObj )
401 GET( GetSingle, SbxSINGLE, float, nSingle )
402 GET( GetULong, SbxULONG, sal_uInt32, nULong )
403 GET( GetUShort, SbxUSHORT, sal_uInt16, nUShort )
404 GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 )
405 GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
406 GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
409 //////////////////////////// Write data
411 bool SbxValue::Put( const SbxValues& rVal )
413 bool bRes = false;
414 ErrCode eOld = GetError();
415 if( eOld != ERRCODE_NONE )
416 ResetError();
417 if( !CanWrite() )
418 SetError( ERRCODE_BASIC_PROP_READONLY );
419 else if( rVal.eType & 0xF000 )
420 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
421 else
423 // If an object is requested, don't search the real values
424 SbxValue* p = this;
425 if( rVal.eType != SbxOBJECT )
426 p = TheRealValue( false ); // Don't allow an error here
427 if( p )
429 if( !p->CanWrite() )
430 SetError( ERRCODE_BASIC_PROP_READONLY );
431 else if( p->IsFixed() || p->SetType( static_cast<SbxDataType>( rVal.eType & 0x0FFF ) ) )
432 switch( rVal.eType & 0x0FFF )
434 case SbxEMPTY:
435 case SbxVOID:
436 case SbxNULL: break;
437 case SbxINTEGER: ImpPutInteger( &p->aData, rVal.nInteger ); break;
438 case SbxLONG: ImpPutLong( &p->aData, rVal.nLong ); break;
439 case SbxSALINT64: ImpPutInt64( &p->aData, rVal.nInt64 ); break;
440 case SbxSALUINT64: ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
441 case SbxSINGLE: ImpPutSingle( &p->aData, rVal.nSingle ); break;
442 case SbxDOUBLE: ImpPutDouble( &p->aData, rVal.nDouble ); break;
443 case SbxCURRENCY: ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
444 case SbxDECIMAL: ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
445 case SbxDATE: ImpPutDate( &p->aData, rVal.nDouble ); break;
446 case SbxBOOL: ImpPutBool( &p->aData, rVal.nInteger ); break;
447 case SbxCHAR: ImpPutChar( &p->aData, rVal.nChar ); break;
448 case SbxBYTE: ImpPutByte( &p->aData, rVal.nByte ); break;
449 case SbxUSHORT: ImpPutUShort( &p->aData, rVal.nUShort ); break;
450 case SbxULONG: ImpPutULong( &p->aData, rVal.nULong ); break;
451 case SbxLPSTR:
452 case SbxSTRING: ImpPutString( &p->aData, rVal.pOUString ); break;
453 case SbxINT:
454 ImpPutLong( &p->aData, static_cast<sal_Int32>(rVal.nInt) );
455 break;
456 case SbxUINT:
457 ImpPutULong( &p->aData, static_cast<sal_uInt32>(rVal.nUInt) );
458 break;
459 case SbxOBJECT:
460 if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
462 // is already inside
463 if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
464 break;
466 // Delete only the value part!
467 p->SbxValue::Clear();
469 // real assignment
470 p->aData.pObj = rVal.pObj;
472 // if necessary increment Ref-Count
473 if( p->aData.pObj && p->aData.pObj != p )
475 if ( p != this )
477 OSL_FAIL( "TheRealValue" );
479 SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
480 SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
481 bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
482 if ( !bParentProp )
483 p->aData.pObj->AddFirstRef();
486 else
487 SetError( ERRCODE_BASIC_CONVERSION );
488 break;
489 default:
490 if( p->aData.eType == rVal.eType )
491 p->aData = rVal;
492 else
494 SetError( ERRCODE_BASIC_CONVERSION );
495 if( !p->IsFixed() )
496 p->aData.eType = SbxNULL;
499 if( !IsError() )
501 p->SetModified( true );
502 p->Broadcast( SfxHintId::BasicDataChanged );
503 if( eOld != ERRCODE_NONE )
504 SetError( eOld );
505 bRes = true;
509 return bRes;
512 // From 1996-03-28:
513 // Method to execute a pretreatment of the strings at special types.
514 // In particular necessary for BASIC-IDE, so that
515 // the output in the Watch-Window can be written back with PutStringExt,
516 // if Float were declared with ',' as the decimal separator or BOOl
517 // explicit with "TRUE" or "FALSE".
518 // Implementation in ImpConvStringExt (SBXSCAN.CXX)
519 void SbxValue::PutStringExt( const OUString& r )
521 // Copy; if it is Unicode convert it immediately
522 OUString aStr( r );
524 // Identify the own type (not as in Put() with TheRealValue(),
525 // Objects are not handled anyway)
526 SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
528 // tinker a Source-Value
529 SbxValues aRes;
530 aRes.eType = SbxSTRING;
532 // Only if really something was converted, take the copy,
533 // otherwise take the original (Unicode remains)
534 bool bRet;
535 if( ImpConvStringExt( aStr, eTargetType ) )
536 aRes.pOUString = &aStr;
537 else
538 aRes.pOUString = const_cast<OUString*>(&r);
540 // #34939: For Strings which contain a number, and if this has a Num-Type,
541 // set a Fixed flag so that the type will not be changed
542 SbxFlagBits nFlags_ = GetFlags();
543 if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
544 ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
545 eTargetType == SbxBOOL )
547 SbxValue aVal;
548 aVal.Put( aRes );
549 if( aVal.IsNumeric() )
550 SetFlag( SbxFlagBits::Fixed );
553 Put( aRes );
554 bRet = bool( !IsError() );
556 // If FIXED resulted in an error, set it back
557 // (UI-Action should not result in an error, but simply fail)
558 if( !bRet )
559 ResetError();
561 SetFlags( nFlags_ );
564 bool SbxValue::PutBool( bool b )
566 SbxValues aRes;
567 aRes.eType = SbxBOOL;
568 aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
569 Put( aRes );
570 return !IsError();
573 bool SbxValue::PutEmpty()
575 bool bRet = SetType( SbxEMPTY );
576 SetModified( true );
577 return bRet;
580 void SbxValue::PutNull()
582 bool bRet = SetType( SbxNULL );
583 if( bRet )
584 SetModified( true );
588 // Special decimal methods
589 void SbxValue::PutDecimal( css::bridge::oleautomation::Decimal const & rAutomationDec )
591 SbxValue::Clear();
592 aData.pDecimal = new SbxDecimal( rAutomationDec );
593 aData.pDecimal->addRef();
594 aData.eType = SbxDECIMAL;
597 void SbxValue::fillAutomationDecimal
598 ( css::bridge::oleautomation::Decimal& rAutomationDec ) const
600 SbxDecimal* pDecimal = GetDecimal();
601 if( pDecimal != nullptr )
603 pDecimal->fillAutomationDecimal( rAutomationDec );
608 bool SbxValue::PutString( const OUString& r )
610 SbxValues aRes;
611 aRes.eType = SbxSTRING;
612 aRes.pOUString = const_cast<OUString*>(&r);
613 Put( aRes );
614 return !IsError();
618 #define PUT( p, e, t, m ) \
619 bool SbxValue::p( t n ) \
620 { SbxValues aRes(e); aRes.m = n; Put( aRes ); return !IsError(); }
622 void SbxValue::PutDate( double n )
623 { SbxValues aRes(SbxDATE); aRes.nDouble = n; Put( aRes ); }
624 void SbxValue::PutErr( sal_uInt16 n )
625 { SbxValues aRes(SbxERROR); aRes.nUShort = n; Put( aRes ); }
627 PUT( PutByte, SbxBYTE, sal_uInt8, nByte )
628 PUT( PutChar, SbxCHAR, sal_Unicode, nChar )
629 PUT( PutCurrency, SbxCURRENCY, sal_Int64, nInt64 )
630 PUT( PutDouble, SbxDOUBLE, double, nDouble )
631 PUT( PutInteger, SbxINTEGER, sal_Int16, nInteger )
632 PUT( PutLong, SbxLONG, sal_Int32, nLong )
633 PUT( PutObject, SbxOBJECT, SbxBase*, pObj )
634 PUT( PutSingle, SbxSINGLE, float, nSingle )
635 PUT( PutULong, SbxULONG, sal_uInt32, nULong )
636 PUT( PutUShort, SbxUSHORT, sal_uInt16, nUShort )
637 PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 )
638 PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
639 PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
641 ////////////////////////// Setting of the data type
643 bool SbxValue::IsFixed() const
645 return (GetFlags() & SbxFlagBits::Fixed) || ((aData.eType & SbxBYREF) != 0);
648 // A variable is numeric, if it is EMPTY or really numeric
649 // or if it contains a complete convertible String
651 // #41692, implement it for RTL and Basic-Core separately
652 bool SbxValue::IsNumeric() const
654 return ImpIsNumeric( /*bOnlyIntntl*/false );
657 bool SbxValue::IsNumericRTL() const
659 return ImpIsNumeric( /*bOnlyIntntl*/true );
662 bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
665 if( !CanRead() )
667 SetError( ERRCODE_BASIC_PROP_WRITEONLY );
668 return false;
670 // Test downcast!!!
671 if( dynamic_cast<const SbxVariable*>( this) != nullptr )
672 const_cast<SbxVariable*>(static_cast<const SbxVariable*>(this))->Broadcast( SfxHintId::BasicDataWanted );
673 SbxDataType t = GetType();
674 if( t == SbxSTRING )
676 if( aData.pOUString )
678 OUString s( *aData.pOUString );
679 double n;
680 SbxDataType t2;
681 sal_uInt16 nLen = 0;
682 if( ImpScan( s, n, t2, &nLen, bOnlyIntntl ) == ERRCODE_NONE )
683 return nLen == s.getLength();
685 return false;
687 else
688 return t == SbxEMPTY
689 || ( t >= SbxINTEGER && t <= SbxCURRENCY )
690 || ( t >= SbxCHAR && t <= SbxUINT );
693 SbxDataType SbxValue::GetType() const
695 return SbxDataType( aData.eType & 0x0FFF );
699 bool SbxValue::SetType( SbxDataType t )
701 DBG_ASSERT( !( t & 0xF000 ), "SetType of BYREF|ARRAY is forbidden!" );
702 if( ( t == SbxEMPTY && aData.eType == SbxVOID )
703 || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
704 return true;
705 if( ( t & 0x0FFF ) == SbxVARIANT )
707 // Try to set the data type to Variant
708 ResetFlag( SbxFlagBits::Fixed );
709 if( IsFixed() )
711 SetError( ERRCODE_BASIC_CONVERSION );
712 return false;
714 t = SbxEMPTY;
716 if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
718 if( !CanWrite() || IsFixed() )
720 SetError( ERRCODE_BASIC_CONVERSION );
721 return false;
723 else
725 // De-allocate potential objects
726 switch( aData.eType )
728 case SbxSTRING:
729 delete aData.pOUString;
730 break;
731 case SbxOBJECT:
732 if( aData.pObj && aData.pObj != this )
734 SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
735 SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
736 sal_uInt32 nSlotId = pThisVar
737 ? pThisVar->GetUserData() & 0xFFFF
738 : 0;
739 DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == "Parent",
740 "SID_PARENTOBJECT is not named 'Parent'" );
741 bool bParentProp = nSlotId == 5345;
742 if ( !bParentProp )
743 aData.pObj->ReleaseRef();
745 break;
746 default: break;
748 aData.clear(t);
751 return true;
754 bool SbxValue::Convert( SbxDataType eTo )
756 eTo = SbxDataType( eTo & 0x0FFF );
757 if( ( aData.eType & 0x0FFF ) == eTo )
758 return true;
759 if( !CanWrite() )
760 return false;
761 if( eTo == SbxVARIANT )
763 // Trial to set the data type to Variant
764 ResetFlag( SbxFlagBits::Fixed );
765 if( IsFixed() )
767 SetError( ERRCODE_BASIC_CONVERSION );
768 return false;
770 else
771 return true;
773 // Converting from null doesn't work. Once null, always null!
774 if( aData.eType == SbxNULL )
776 SetError( ERRCODE_BASIC_CONVERSION );
777 return false;
780 // Conversion of the data:
781 SbxValues aNew;
782 aNew.eType = eTo;
783 if( Get( aNew ) )
785 // The data type could be converted. It ends here with fixed elements,
786 // because the data had not to be taken over
787 if( !IsFixed() )
789 SetType( eTo );
790 Put( aNew );
791 SetModified( true );
793 return true;
795 else
796 return false;
798 ////////////////////////////////// Calculating
800 bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
802 #if !HAVE_FEATURE_SCRIPTING
803 const bool bVBAInterop = false;
804 #else
805 bool bVBAInterop = SbiRuntime::isVBAEnabled();
806 #endif
807 SbxDataType eThisType = GetType();
808 SbxDataType eOpType = rOp.GetType();
809 ErrCode eOld = GetError();
810 if( eOld != ERRCODE_NONE )
811 ResetError();
812 if( !CanWrite() )
813 SetError( ERRCODE_BASIC_PROP_READONLY );
814 else if( !rOp.CanRead() )
815 SetError( ERRCODE_BASIC_PROP_WRITEONLY );
816 // Special rule 1: If one operand is null, the result is null
817 else if( eThisType == SbxNULL || eOpType == SbxNULL )
818 SetType( SbxNULL );
819 else
821 SbxValues aL, aR;
822 bool bDecimal = false;
823 if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
824 ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
825 ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
827 goto Lbl_OpIsDouble;
829 else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && ( eOp == SbxPLUS ) ) )
831 if( eOp == SbxCAT || eOp == SbxPLUS )
833 // From 1999-11-5, keep OUString in mind
834 aL.eType = aR.eType = SbxSTRING;
835 rOp.Get( aR );
836 // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
837 if( rOp.GetType() == SbxEMPTY )
838 goto Lbl_OpIsEmpty; // concatenate empty, *this stays lhs as result
839 Get( aL );
841 // #30576: To begin with test, if the conversion worked
842 if( aL.pOUString != nullptr && aR.pOUString != nullptr )
844 // tdf#108039: catch possible bad_alloc
845 try {
846 *aL.pOUString += *aR.pOUString;
848 catch (const std::bad_alloc&) {
849 SetError(ERRCODE_BASIC_MATH_OVERFLOW);
852 // Not even Left OK?
853 else if( aL.pOUString == nullptr )
855 aL.pOUString = new OUString();
858 else
859 SetError( ERRCODE_BASIC_CONVERSION );
861 else if( eOpType == SbxSTRING && rOp.IsFixed() )
862 { // Numeric: there is no String allowed on the right side
863 SetError( ERRCODE_BASIC_CONVERSION );
864 // falls all the way out
866 else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
868 if( GetType() == eOpType )
870 if( GetType() == SbxSALUINT64 || GetType() == SbxSALINT64
871 || GetType() == SbxCURRENCY || GetType() == SbxULONG )
872 aL.eType = aR.eType = GetType();
873 else if ( bVBAInterop && eOpType == SbxBOOL )
874 aL.eType = aR.eType = SbxBOOL;
875 else
876 aL.eType = aR.eType = SbxLONG;
878 else
879 aL.eType = aR.eType = SbxLONG;
881 if( rOp.Get( aR ) ) // re-do Get after type assigns above
883 if( Get( aL ) ) switch( eOp )
885 /* TODO: For SbxEMPTY operands with boolean operators use
886 * the VBA Nothing definition of Comparing Nullable Types?
887 * https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/nullable-value-types
889 /* TODO: it is unclear yet whether this also should be done
890 * for the non-bVBAInterop case or not, or at all, consider
891 * user defined spreadsheet functions where an empty cell
892 * is SbxEMPTY and usually is treated as 0 zero or "" empty
893 * string.
895 case SbxIDIV:
896 if( aL.eType == SbxCURRENCY )
897 if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
898 else {
899 aL.nInt64 /= aR.nInt64;
900 aL.nInt64 *= CURRENCY_FACTOR;
902 else if( aL.eType == SbxSALUINT64 )
903 if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
904 else aL.uInt64 /= aR.uInt64;
905 else if( aL.eType == SbxSALINT64 )
906 if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
907 else aL.nInt64 /= aR.nInt64;
908 else if( aL.eType == SbxLONG )
909 if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
910 else aL.nLong /= aR.nLong;
911 else
912 if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
913 else aL.nULong /= aR.nULong;
914 break;
915 case SbxMOD:
916 if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
917 if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
918 else aL.nInt64 %= aR.nInt64;
919 else if( aL.eType == SbxSALUINT64 )
920 if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
921 else aL.uInt64 %= aR.uInt64;
922 else if( aL.eType == SbxLONG )
923 if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
924 else aL.nLong %= aR.nLong;
925 else
926 if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
927 else aL.nULong %= aR.nULong;
928 break;
929 case SbxAND:
930 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
931 aL.nInt64 &= aR.nInt64;
932 else
933 aL.nLong &= aR.nLong;
934 break;
935 case SbxOR:
936 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
937 aL.nInt64 |= aR.nInt64;
938 else
939 aL.nLong |= aR.nLong;
940 break;
941 case SbxXOR:
942 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
943 aL.nInt64 ^= aR.nInt64;
944 else
945 aL.nLong ^= aR.nLong;
946 break;
947 case SbxEQV:
948 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
949 aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
950 else
951 aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
952 break;
953 case SbxIMP:
954 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
955 aL.nInt64 = ~aL.nInt64 | aR.nInt64;
956 else
957 aL.nLong = ~aL.nLong | aR.nLong;
958 break;
959 case SbxNOT:
960 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
962 if ( aL.eType != SbxBOOL )
963 aL.nInt64 = ~aL.nInt64;
964 else
965 aL.nLong = ~aL.nLong;
967 else
968 aL.nLong = ~aL.nLong;
969 break;
970 default: break;
974 else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
975 && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
977 aL.eType = aR.eType = SbxDECIMAL;
978 bDecimal = true;
979 if( rOp.Get( aR ) && Get( aL ) )
981 if( aL.pDecimal && aR.pDecimal )
983 bool bOk = true;
984 switch( eOp )
986 case SbxMUL:
987 bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
988 break;
989 case SbxDIV:
990 if( aR.pDecimal->isZero() )
991 SetError( ERRCODE_BASIC_ZERODIV );
992 else
993 bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
994 break;
995 case SbxPLUS:
996 bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
997 break;
998 case SbxMINUS:
999 bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
1000 break;
1001 case SbxNEG:
1002 bOk = ( aL.pDecimal->neg() );
1003 break;
1004 default:
1005 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1007 if( !bOk )
1008 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1010 else
1012 SetError( ERRCODE_BASIC_CONVERSION );
1016 else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
1018 aL.eType = SbxCURRENCY;
1019 aR.eType = SbxCURRENCY;
1021 if( rOp.Get( aR ) )
1023 if( Get( aL ) ) switch( eOp )
1025 case SbxMUL:
1027 // first overflow check: see if product will fit - test real value of product (hence 2 curr factors)
1028 double dTest = static_cast<double>(aL.nInt64) * static_cast<double>(aR.nInt64) / double(CURRENCY_FACTOR_SQUARE);
1029 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1031 aL.nInt64 = SAL_MAX_INT64;
1032 if( dTest < SbxMINCURR ) aL.nInt64 = SAL_MIN_INT64;
1033 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1034 break;
1036 // second overflow check: see if unscaled product overflows - if so use doubles
1037 dTest = static_cast<double>(aL.nInt64) * static_cast<double>(aR.nInt64);
1038 if( !(o3tl::convertsToAtLeast(dTest, SAL_MIN_INT64)
1039 && o3tl::convertsToAtMost(dTest, SAL_MAX_INT64)))
1041 aL.nInt64 = static_cast<sal_Int64>( dTest / double(CURRENCY_FACTOR) );
1042 break;
1044 // precise calc: multiply then scale back (move decimal pt)
1045 aL.nInt64 *= aR.nInt64;
1046 aL.nInt64 /= CURRENCY_FACTOR;
1047 break;
1050 case SbxDIV:
1052 if( !aR.nInt64 )
1054 SetError( ERRCODE_BASIC_ZERODIV );
1055 break;
1057 // first overflow check: see if quotient will fit - calc real value of quotient (curr factors cancel)
1058 double dTest = static_cast<double>(aL.nInt64) / static_cast<double>(aR.nInt64);
1059 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1061 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1062 break;
1064 // second overflow check: see if scaled dividend overflows - if so use doubles
1065 dTest = static_cast<double>(aL.nInt64) * double(CURRENCY_FACTOR);
1066 if( !(o3tl::convertsToAtLeast(dTest, SAL_MIN_INT64)
1067 && o3tl::convertsToAtMost(dTest, SAL_MAX_INT64)))
1069 aL.nInt64 = static_cast<sal_Int64>(dTest / static_cast<double>(aR.nInt64));
1070 break;
1072 // precise calc: scale (move decimal pt) then divide
1073 aL.nInt64 *= CURRENCY_FACTOR;
1074 aL.nInt64 /= aR.nInt64;
1075 break;
1078 case SbxPLUS:
1080 double dTest = ( static_cast<double>(aL.nInt64) + static_cast<double>(aR.nInt64) ) / double(CURRENCY_FACTOR);
1081 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1083 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1084 break;
1086 aL.nInt64 += aR.nInt64;
1087 break;
1090 case SbxMINUS:
1092 double dTest = ( static_cast<double>(aL.nInt64) - static_cast<double>(aR.nInt64) ) / double(CURRENCY_FACTOR);
1093 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1095 SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1096 break;
1098 aL.nInt64 -= aR.nInt64;
1099 break;
1101 case SbxNEG:
1102 aL.nInt64 = -aL.nInt64;
1103 break;
1104 default:
1105 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1109 else
1110 Lbl_OpIsDouble:
1111 { // other types and operators including Date, Double and Single
1112 aL.eType = aR.eType = SbxDOUBLE;
1113 if( rOp.Get( aR ) )
1115 if( Get( aL ) )
1117 switch( eOp )
1119 case SbxEXP:
1120 aL.nDouble = pow( aL.nDouble, aR.nDouble );
1121 break;
1122 case SbxMUL:
1123 aL.nDouble *= aR.nDouble; break;
1124 case SbxDIV:
1125 if( !aR.nDouble ) SetError( ERRCODE_BASIC_ZERODIV );
1126 else aL.nDouble /= aR.nDouble;
1127 break;
1128 case SbxPLUS:
1129 aL.nDouble += aR.nDouble; break;
1130 case SbxMINUS:
1131 aL.nDouble -= aR.nDouble; break;
1132 case SbxNEG:
1133 aL.nDouble = -aL.nDouble; break;
1134 default:
1135 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1137 // Date with "+" or "-" needs special handling that
1138 // forces the Date type. If the operation is '+' the
1139 // result is always a Date, if '-' the result is only
1140 // a Date if one of lhs or rhs ( but not both ) is already
1141 // a Date
1142 if( GetType() == SbxDATE || rOp.GetType() == SbxDATE )
1144 if( eOp == SbxPLUS || ( ( eOp == SbxMINUS ) && ( GetType() != rOp.GetType() ) ) )
1145 aL.eType = SbxDATE;
1152 if( !IsError() )
1153 Put( aL );
1154 if( bDecimal )
1156 releaseDecimalPtr( aL.pDecimal );
1157 releaseDecimalPtr( aR.pDecimal );
1160 Lbl_OpIsEmpty:
1162 bool bRes = !IsError();
1163 if( bRes && eOld != ERRCODE_NONE )
1164 SetError( eOld );
1165 return bRes;
1168 // The comparison routine deliver TRUE or FALSE.
1170 bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1172 #if !HAVE_FEATURE_SCRIPTING
1173 const bool bVBAInterop = false;
1174 #else
1175 bool bVBAInterop = SbiRuntime::isVBAEnabled();
1176 #endif
1178 bool bRes = false;
1179 ErrCode eOld = GetError();
1180 if( eOld != ERRCODE_NONE )
1181 ResetError();
1182 if( !CanRead() || !rOp.CanRead() )
1183 SetError( ERRCODE_BASIC_PROP_WRITEONLY );
1184 else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1186 bRes = true;
1188 else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1189 bRes = !bVBAInterop || ( eOp == SbxEQ );
1190 // Special rule 1: If an operand is null, the result is FALSE
1191 else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1192 bRes = false;
1193 // Special rule 2: If both are variant and one is numeric
1194 // and the other is a String, num is < str
1195 else if( !IsFixed() && !rOp.IsFixed()
1196 && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1198 bRes = eOp == SbxLT || eOp == SbxLE || eOp == SbxNE;
1199 else if( !IsFixed() && !rOp.IsFixed()
1200 && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1201 && !bVBAInterop
1203 bRes = eOp == SbxGT || eOp == SbxGE || eOp == SbxNE;
1204 else
1206 SbxValues aL, aR;
1207 // If one of the operands is a String,
1208 // a String comparing take place
1209 if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1211 aL.eType = aR.eType = SbxSTRING;
1212 if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
1214 case SbxEQ:
1215 bRes = ( *aL.pOUString == *aR.pOUString ); break;
1216 case SbxNE:
1217 bRes = ( *aL.pOUString != *aR.pOUString ); break;
1218 case SbxLT:
1219 bRes = ( *aL.pOUString < *aR.pOUString ); break;
1220 case SbxGT:
1221 bRes = ( *aL.pOUString > *aR.pOUString ); break;
1222 case SbxLE:
1223 bRes = ( *aL.pOUString <= *aR.pOUString ); break;
1224 case SbxGE:
1225 bRes = ( *aL.pOUString >= *aR.pOUString ); break;
1226 default:
1227 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1230 // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1231 // otherwise it shows a numeric error
1232 else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1234 aL.eType = aR.eType = SbxSINGLE;
1235 if( Get( aL ) && rOp.Get( aR ) )
1236 switch( eOp )
1238 case SbxEQ:
1239 bRes = ( aL.nSingle == aR.nSingle ); break;
1240 case SbxNE:
1241 bRes = ( aL.nSingle != aR.nSingle ); break;
1242 case SbxLT:
1243 bRes = ( aL.nSingle < aR.nSingle ); break;
1244 case SbxGT:
1245 bRes = ( aL.nSingle > aR.nSingle ); break;
1246 case SbxLE:
1247 bRes = ( aL.nSingle <= aR.nSingle ); break;
1248 case SbxGE:
1249 bRes = ( aL.nSingle >= aR.nSingle ); break;
1250 default:
1251 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1254 else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1256 aL.eType = aR.eType = SbxDECIMAL;
1257 Get( aL );
1258 rOp.Get( aR );
1259 if( aL.pDecimal && aR.pDecimal )
1261 SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1262 switch( eOp )
1264 case SbxEQ:
1265 bRes = ( eRes == SbxDecimal::CmpResult::EQ ); break;
1266 case SbxNE:
1267 bRes = ( eRes != SbxDecimal::CmpResult::EQ ); break;
1268 case SbxLT:
1269 bRes = ( eRes == SbxDecimal::CmpResult::LT ); break;
1270 case SbxGT:
1271 bRes = ( eRes == SbxDecimal::CmpResult::GT ); break;
1272 case SbxLE:
1273 bRes = ( eRes != SbxDecimal::CmpResult::GT ); break;
1274 case SbxGE:
1275 bRes = ( eRes != SbxDecimal::CmpResult::LT ); break;
1276 default:
1277 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1280 else
1282 SetError( ERRCODE_BASIC_CONVERSION );
1284 releaseDecimalPtr( aL.pDecimal );
1285 releaseDecimalPtr( aR.pDecimal );
1287 // Everything else comparing on a SbxDOUBLE-Basis
1288 else
1290 aL.eType = aR.eType = SbxDOUBLE;
1291 bool bGetL = Get( aL );
1292 bool bGetR = rOp.Get( aR );
1293 if( bGetL && bGetR )
1294 switch( eOp )
1296 case SbxEQ:
1297 bRes = ( aL.nDouble == aR.nDouble ); break;
1298 case SbxNE:
1299 bRes = ( aL.nDouble != aR.nDouble ); break;
1300 case SbxLT:
1301 bRes = ( aL.nDouble < aR.nDouble ); break;
1302 case SbxGT:
1303 bRes = ( aL.nDouble > aR.nDouble ); break;
1304 case SbxLE:
1305 bRes = ( aL.nDouble <= aR.nDouble ); break;
1306 case SbxGE:
1307 bRes = ( aL.nDouble >= aR.nDouble ); break;
1308 default:
1309 SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1311 // at least one value was got
1312 // if this is VBA then a conversion error for one
1313 // side will yield a false result of an equality test
1314 else if ( bGetR || bGetL )
1316 if ( bVBAInterop && eOp == SbxEQ && GetError() == ERRCODE_BASIC_CONVERSION )
1318 #ifndef IOS
1319 ResetError();
1320 bRes = false;
1321 #endif
1326 if( eOld != ERRCODE_NONE )
1327 SetError( eOld );
1328 return bRes;
1331 ///////////////////////////// Reading/Writing
1333 bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1335 // #TODO see if these types are really dumped to any stream
1336 // more than likely this is functionality used in the binfilter alone
1337 SbxValue::Clear();
1338 sal_uInt16 nType;
1339 r.ReadUInt16( nType );
1340 aData.eType = SbxDataType( nType );
1341 switch( nType )
1343 case SbxBOOL:
1344 case SbxINTEGER:
1345 r.ReadInt16( aData.nInteger ); break;
1346 case SbxLONG:
1347 r.ReadInt32( aData.nLong ); break;
1348 case SbxSINGLE:
1350 // Floats as ASCII
1351 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1352 RTL_TEXTENCODING_ASCII_US);
1353 double d;
1354 SbxDataType t;
1355 if( ImpScan( aVal, d, t, nullptr, false ) != ERRCODE_NONE || t == SbxDOUBLE )
1357 aData.nSingle = 0.0F;
1358 return false;
1360 aData.nSingle = static_cast<float>(d);
1361 break;
1363 case SbxDATE:
1364 case SbxDOUBLE:
1366 // Floats as ASCII
1367 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1368 RTL_TEXTENCODING_ASCII_US);
1369 SbxDataType t;
1370 if( ImpScan( aVal, aData.nDouble, t, nullptr, false ) != ERRCODE_NONE )
1372 aData.nDouble = 0.0;
1373 return false;
1375 break;
1377 case SbxSALINT64:
1378 r.ReadInt64(aData.nInt64);
1379 break;
1380 case SbxSALUINT64:
1381 r.ReadUInt64( aData.uInt64 );
1382 break;
1383 case SbxCURRENCY:
1385 sal_uInt32 tmpHi = 0;
1386 sal_uInt32 tmpLo = 0;
1387 r.ReadUInt32( tmpHi ).ReadUInt32( tmpLo );
1388 aData.nInt64 = (static_cast<sal_Int64>(tmpHi) << 32);
1389 aData.nInt64 |= static_cast<sal_Int64>(tmpLo);
1390 break;
1392 case SbxSTRING:
1394 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1395 RTL_TEXTENCODING_ASCII_US);
1396 if( !aVal.isEmpty() )
1397 aData.pOUString = new OUString( aVal );
1398 else
1399 aData.pOUString = nullptr; // JSM 1995-09-22
1400 break;
1402 case SbxERROR:
1403 case SbxUSHORT:
1404 r.ReadUInt16( aData.nUShort ); break;
1405 case SbxOBJECT:
1407 sal_uInt8 nMode;
1408 r.ReadUChar( nMode );
1409 switch( nMode )
1411 case 0:
1412 aData.pObj = nullptr;
1413 break;
1414 case 1:
1415 aData.pObj = SbxBase::Load( r );
1416 return ( aData.pObj != nullptr );
1417 case 2:
1418 aData.pObj = this;
1419 break;
1421 break;
1423 case SbxCHAR:
1425 char c;
1426 r.ReadChar( c );
1427 aData.nChar = c;
1428 break;
1430 case SbxBYTE:
1431 r.ReadUChar( aData.nByte ); break;
1432 case SbxULONG:
1433 r.ReadUInt32( aData.nULong ); break;
1434 case SbxINT:
1436 sal_uInt8 n;
1437 r.ReadUChar( n );
1438 // Match the Int on this system?
1439 if( n > SAL_TYPES_SIZEOFINT )
1441 r.ReadInt32( aData.nLong );
1442 aData.eType = SbxLONG;
1444 else {
1445 sal_Int32 nInt;
1446 r.ReadInt32( nInt );
1447 aData.nInt = nInt;
1449 break;
1451 case SbxUINT:
1453 sal_uInt8 n;
1454 r.ReadUChar( n );
1455 // Match the UInt on this system?
1456 if( n > SAL_TYPES_SIZEOFINT )
1458 r.ReadUInt32( aData.nULong );
1459 aData.eType = SbxULONG;
1461 else {
1462 sal_uInt32 nUInt;
1463 r.ReadUInt32( nUInt );
1464 aData.nUInt = nUInt;
1466 break;
1468 case SbxEMPTY:
1469 case SbxNULL:
1470 case SbxVOID:
1471 break;
1472 case SbxDATAOBJECT:
1473 r.ReadInt32( aData.nLong );
1474 break;
1475 // #78919 For backwards compatibility
1476 case SbxWSTRING:
1477 case SbxWCHAR:
1478 break;
1479 default:
1480 aData.clear(SbxNULL);
1481 ResetFlag(SbxFlagBits::Fixed);
1482 SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
1484 return false;
1486 return true;
1489 bool SbxValue::StoreData( SvStream& r ) const
1491 sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1492 r.WriteUInt16( nType );
1493 switch( nType & 0x0FFF )
1495 case SbxBOOL:
1496 case SbxINTEGER:
1497 r.WriteInt16( aData.nInteger ); break;
1498 case SbxLONG:
1499 r.WriteInt32( aData.nLong ); break;
1500 case SbxDATE:
1501 // #49935: Save as double, otherwise an error during the read in
1502 const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>( ( nType & 0xF000 ) | SbxDOUBLE );
1503 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1504 const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>(nType);
1505 break;
1506 case SbxSINGLE:
1507 case SbxDOUBLE:
1508 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1509 break;
1510 case SbxSALUINT64:
1511 case SbxSALINT64:
1512 // see comment in SbxValue::StoreData
1513 r.WriteUInt64( aData.uInt64 );
1514 break;
1515 case SbxCURRENCY:
1517 sal_Int32 tmpHi = ( (aData.nInt64 >> 32) & 0xFFFFFFFF );
1518 sal_Int32 tmpLo = static_cast<sal_Int32>(aData.nInt64);
1519 r.WriteInt32( tmpHi ).WriteInt32( tmpLo );
1520 break;
1522 case SbxSTRING:
1523 if( aData.pOUString )
1525 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1527 else
1529 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, OUString(), RTL_TEXTENCODING_ASCII_US);
1531 break;
1532 case SbxERROR:
1533 case SbxUSHORT:
1534 r.WriteUInt16( aData.nUShort ); break;
1535 case SbxOBJECT:
1536 // to save itself as Objectptr does not work!
1537 if( aData.pObj )
1539 if( dynamic_cast<SbxValue*>( aData.pObj) != this )
1541 r.WriteUChar( 1 );
1542 return aData.pObj->Store( r );
1544 else
1545 r.WriteUChar( 2 );
1547 else
1548 r.WriteUChar( 0 );
1549 break;
1550 case SbxCHAR:
1552 char c = sal::static_int_cast< char >(aData.nChar);
1553 r.WriteChar( c );
1554 break;
1556 case SbxBYTE:
1557 r.WriteUChar( aData.nByte ); break;
1558 case SbxULONG:
1559 r.WriteUInt32( aData.nULong ); break;
1560 case SbxINT:
1562 r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteInt32( aData.nInt );
1563 break;
1565 case SbxUINT:
1567 r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteUInt32( aData.nUInt );
1568 break;
1570 case SbxEMPTY:
1571 case SbxNULL:
1572 case SbxVOID:
1573 break;
1574 case SbxDATAOBJECT:
1575 r.WriteInt32( aData.nLong );
1576 break;
1577 // #78919 For backwards compatibility
1578 case SbxWSTRING:
1579 case SbxWCHAR:
1580 break;
1581 default:
1582 SAL_WARN( "basic.sbx", "Saving a non-supported data type" );
1583 return false;
1585 return true;
1588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */