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