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