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
