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 <stdlib.h> 21 22 #include <algorithm> 23 #include <string_view> 24 #include <unordered_map> 25 26 #include <com/sun/star/beans/XPropertySet.hpp> 27 #include <com/sun/star/container/XEnumerationAccess.hpp> 28 #include <com/sun/star/container/XIndexAccess.hpp> 29 #include <com/sun/star/script/XDefaultMethod.hpp> 30 #include <com/sun/star/uno/Any.hxx> 31 #include <com/sun/star/util/SearchAlgorithms2.hpp> 32 33 #include <comphelper/processfactory.hxx> 34 #include <comphelper/string.hxx> 35 #include <o3tl/safeint.hxx> 36 #include <sal/log.hxx> 37 38 #include <tools/wldcrd.hxx> 39 #include <tools/diagnose_ex.h> 40 41 #include <vcl/svapp.hxx> 42 #include <vcl/settings.hxx> 43 44 #include <rtl/instance.hxx> 45 #include <rtl/math.hxx> 46 #include <rtl/ustrbuf.hxx> 47 #include <rtl/character.hxx> 48 49 #include <svl/numformat.hxx> 50 #include <svl/zforlist.hxx> 51 52 #include <i18nutil/searchopt.hxx> 53 #include <unotools/syslocale.hxx> 54 #include <unotools/textsearch.hxx> 55 56 #include <basic/sbuno.hxx> 57 58 #include <codegen.hxx> 59 #include "comenumwrapper.hxx" 60 #include "ddectrl.hxx" 61 #include "dllmgr.hxx" 62 #include <errobject.hxx> 63 #include <image.hxx> 64 #include <iosys.hxx> 65 #include <opcodes.hxx> 66 #include <runtime.hxx> 67 #include <sb.hxx> 68 #include <sbintern.hxx> 69 #include <sbprop.hxx> 70 #include <sbunoobj.hxx> 71 #include <basic/codecompletecache.hxx> 72 #include <memory> 73 74 using com::sun::star::uno::Reference; 75 76 using namespace com::sun::star::uno; 77 using namespace com::sun::star::container; 78 using namespace com::sun::star::lang; 79 using namespace com::sun::star::beans; 80 using namespace com::sun::star::script; 81 82 using namespace ::com::sun::star; 83 84 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType ); 85 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled ); 86 87 namespace 88 { 89 class ScopedWritableGuard 90 { 91 public: 92 ScopedWritableGuard(const SbxVariableRef& rVar, bool bMakeWritable) 93 : m_rVar(rVar) 94 , m_bReset(bMakeWritable && !rVar->CanWrite()) 95 { 96 if (m_bReset) 97 { 98 m_rVar->SetFlag(SbxFlagBits::Write); 99 } 100 } 101 ~ScopedWritableGuard() 102 { 103 if (m_bReset) 104 { 105 m_rVar->ResetFlag(SbxFlagBits::Write); 106 } 107 } 108 109 private: 110 SbxVariableRef m_rVar; 111 bool m_bReset; 112 }; 113 } 114 115 bool SbiRuntime::isVBAEnabled() 116 { 117 bool bResult = false; 118 SbiInstance* pInst = GetSbData()->pInst; 119 if ( pInst && GetSbData()->pInst->pRun ) 120 bResult = pInst->pRun->bVBAEnabled; 121 return bResult; 122 } 123 124 void StarBASIC::SetVBAEnabled( bool bEnabled ) 125 { 126 if ( bDocBasic ) 127 { 128 bVBAEnabled = bEnabled; 129 } 130 } 131 132 bool StarBASIC::isVBAEnabled() const 133 { 134 if ( bDocBasic ) 135 { 136 if( SbiRuntime::isVBAEnabled() ) 137 return true; 138 return bVBAEnabled; 139 } 140 return false; 141 } 142 143 struct SbiArgv { // Argv stack: 144 SbxArrayRef refArgv; // Argv 145 short nArgc; // Argc 146 147 SbiArgv(SbxArrayRef const & refArgv_, short nArgc_) : 148 refArgv(refArgv_), 149 nArgc(nArgc_) {} 150 }; 151 152 struct SbiGosub { // GOSUB-Stack: 153 const sal_uInt8* pCode; // Return-Pointer 154 sal_uInt16 nStartForLvl; // #118235: For Level in moment of gosub 155 156 SbiGosub(const sal_uInt8* pCode_, sal_uInt16 nStartForLvl_) : 157 pCode(pCode_), 158 nStartForLvl(nStartForLvl_) {} 159 }; 160 161 const SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // all opcodes without operands 162 &SbiRuntime::StepNOP, 163 &SbiRuntime::StepEXP, 164 &SbiRuntime::StepMUL, 165 &SbiRuntime::StepDIV, 166 &SbiRuntime::StepMOD, 167 &SbiRuntime::StepPLUS, 168 &SbiRuntime::StepMINUS, 169 &SbiRuntime::StepNEG, 170 &SbiRuntime::StepEQ, 171 &SbiRuntime::StepNE, 172 &SbiRuntime::StepLT, 173 &SbiRuntime::StepGT, 174 &SbiRuntime::StepLE, 175 &SbiRuntime::StepGE, 176 &SbiRuntime::StepIDIV, 177 &SbiRuntime::StepAND, 178 &SbiRuntime::StepOR, 179 &SbiRuntime::StepXOR, 180 &SbiRuntime::StepEQV, 181 &SbiRuntime::StepIMP, 182 &SbiRuntime::StepNOT, 183 &SbiRuntime::StepCAT, 184 185 &SbiRuntime::StepLIKE, 186 &SbiRuntime::StepIS, 187 // load/save 188 &SbiRuntime::StepARGC, // establish new Argv 189 &SbiRuntime::StepARGV, // TOS ==> current Argv 190 &SbiRuntime::StepINPUT, // Input ==> TOS 191 &SbiRuntime::StepLINPUT, // Line Input ==> TOS 192 &SbiRuntime::StepGET, // touch TOS 193 &SbiRuntime::StepSET, // save object TOS ==> TOS-1 194 &SbiRuntime::StepPUT, // TOS ==> TOS-1 195 &SbiRuntime::StepPUTC, // TOS ==> TOS-1, then ReadOnly 196 &SbiRuntime::StepDIM, // DIM 197 &SbiRuntime::StepREDIM, // REDIM 198 &SbiRuntime::StepREDIMP, // REDIM PRESERVE 199 &SbiRuntime::StepERASE, // delete TOS 200 // branch 201 &SbiRuntime::StepSTOP, // program end 202 &SbiRuntime::StepINITFOR, // initialize FOR-Variable 203 &SbiRuntime::StepNEXT, // increment FOR-Variable 204 &SbiRuntime::StepCASE, // beginning CASE 205 &SbiRuntime::StepENDCASE, // end CASE 206 &SbiRuntime::StepSTDERROR, // standard error handling 207 &SbiRuntime::StepNOERROR, // no error handling 208 &SbiRuntime::StepLEAVE, // leave UP 209 // E/A 210 &SbiRuntime::StepCHANNEL, // TOS = channel number 211 &SbiRuntime::StepPRINT, // print TOS 212 &SbiRuntime::StepPRINTF, // print TOS in field 213 &SbiRuntime::StepWRITE, // write TOS 214 &SbiRuntime::StepRENAME, // Rename Tos+1 to Tos 215 &SbiRuntime::StepPROMPT, // define Input Prompt from TOS 216 &SbiRuntime::StepRESTART, // Set restart point 217 &SbiRuntime::StepCHANNEL0, // set E/A-channel 0 218 &SbiRuntime::StepEMPTY, // empty expression on stack 219 &SbiRuntime::StepERROR, // TOS = error code 220 &SbiRuntime::StepLSET, // save object TOS ==> TOS-1 221 &SbiRuntime::StepRSET, // save object TOS ==> TOS-1 222 &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP 223 &SbiRuntime::StepINITFOREACH,// Init for each loop 224 &SbiRuntime::StepVBASET,// vba-like set statement 225 &SbiRuntime::StepERASE_CLEAR,// vba-like set statement 226 &SbiRuntime::StepARRAYACCESS,// access TOS as array 227 &SbiRuntime::StepBYVAL, // access TOS as array 228 }; 229 230 const SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // all opcodes with one operand 231 &SbiRuntime::StepLOADNC, // loading a numeric constant (+ID) 232 &SbiRuntime::StepLOADSC, // loading a string constant (+ID) 233 &SbiRuntime::StepLOADI, // Immediate Load (+value) 234 &SbiRuntime::StepARGN, // save a named Args in Argv (+StringID) 235 &SbiRuntime::StepPAD, // bring string to a definite length (+length) 236 // branches 237 &SbiRuntime::StepJUMP, // jump (+Target) 238 &SbiRuntime::StepJUMPT, // evaluate TOS, conditional jump (+Target) 239 &SbiRuntime::StepJUMPF, // evaluate TOS, conditional jump (+Target) 240 &SbiRuntime::StepONJUMP, // evaluate TOS, jump into JUMP-table (+MaxVal) 241 &SbiRuntime::StepGOSUB, // UP-call (+Target) 242 &SbiRuntime::StepRETURN, // UP-return (+0 or Target) 243 &SbiRuntime::StepTESTFOR, // check FOR-variable, increment (+Endlabel) 244 &SbiRuntime::StepCASETO, // Tos+1 <= Case <= Tos), 2xremove (+Target) 245 &SbiRuntime::StepERRHDL, // error handler (+Offset) 246 &SbiRuntime::StepRESUME, // resume after errors (+0 or 1 or Label) 247 // E/A 248 &SbiRuntime::StepCLOSE, // (+channel/0) 249 &SbiRuntime::StepPRCHAR, // (+char) 250 // management 251 &SbiRuntime::StepSETCLASS, // check set + class names (+StringId) 252 &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId) 253 &SbiRuntime::StepLIB, // lib for declare-call (+StringId) 254 &SbiRuntime::StepBASED, // TOS is incremented by BASE, BASE is pushed before 255 &SbiRuntime::StepARGTYP, // convert last parameter in Argv (+Type) 256 &SbiRuntime::StepVBASETCLASS,// vba-like set statement 257 }; 258 259 const SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// all opcodes with two operands 260 &SbiRuntime::StepRTL, // load from RTL (+StringID+Typ) 261 &SbiRuntime::StepFIND, // load (+StringID+Typ) 262 &SbiRuntime::StepELEM, // load element (+StringID+Typ) 263 &SbiRuntime::StepPARAM, // Parameter (+Offset+Typ) 264 // branches 265 &SbiRuntime::StepCALL, // Declare-Call (+StringID+Typ) 266 &SbiRuntime::StepCALLC, // CDecl-Declare-Call (+StringID+Typ) 267 &SbiRuntime::StepCASEIS, // Case-Test (+Test-Opcode+False-Target) 268 // management 269 &SbiRuntime::StepSTMNT, // beginning of a statement (+Line+Col) 270 // E/A 271 &SbiRuntime::StepOPEN, // (+StreamMode+Flags) 272 // Objects 273 &SbiRuntime::StepLOCAL, // define local variable (+StringId+Typ) 274 &SbiRuntime::StepPUBLIC, // module global variable (+StringID+Typ) 275 &SbiRuntime::StepGLOBAL, // define global variable (+StringID+Typ) 276 &SbiRuntime::StepCREATE, // create object (+StringId+StringId) 277 &SbiRuntime::StepSTATIC, // static variable (+StringId+StringId) 278 &SbiRuntime::StepTCREATE, // user-defined objects (+StringId+StringId) 279 &SbiRuntime::StepDCREATE, // create object-array (+StringID+StringID) 280 &SbiRuntime::StepGLOBAL_P, // define global variable which is not overwritten 281 // by the Basic on a restart (+StringID+Typ) 282 &SbiRuntime::StepFIND_G, // finds global variable with special treatment because of _GLOBAL_P 283 &SbiRuntime::StepDCREATE_REDIMP, // redimension object array (+StringID+StringID) 284 &SbiRuntime::StepFIND_CM, // Search inside a class module (CM) to enable global search in time 285 &SbiRuntime::StepPUBLIC_P, // Search inside a class module (CM) to enable global search in time 286 &SbiRuntime::StepFIND_STATIC, // Search inside a class module (CM) to enable global search in time 287 }; 288 289 290 // SbiRTLData 291 292 SbiRTLData::SbiRTLData() 293 { 294 nDirFlags = SbAttributes::NONE; 295 nCurDirPos = 0; 296 } 297 298 SbiRTLData::~SbiRTLData() 299 { 300 } 301 302 // SbiInstance 303 304 // 16.10.96: #31460 new concept for StepInto/Over/Out 305 // The decision whether StepPoint shall be called is done with the help of 306 // the CallLevel. It's stopped when the current CallLevel is <= nBreakCallLvl. 307 // The current CallLevel can never be smaller than 1, as it's also incremented 308 // during the call of a method (also main). Therefore a BreakCallLvl from 0 309 // means that the program isn't stopped at all. 310 // (also have a look at: step2.cxx, SbiRuntime::StepSTMNT() ) 311 312 313 void SbiInstance::CalcBreakCallLevel( BasicDebugFlags nFlags ) 314 { 315 316 nFlags &= ~BasicDebugFlags::Break; 317 318 sal_uInt16 nRet; 319 if (nFlags == BasicDebugFlags::StepInto) { 320 nRet = nCallLvl + 1; // CallLevel+1 is also stopped 321 } else if (nFlags == (BasicDebugFlags::StepOver | BasicDebugFlags::StepInto)) { 322 nRet = nCallLvl; // current CallLevel is stopped 323 } else if (nFlags == BasicDebugFlags::StepOut) { 324 nRet = nCallLvl - 1; // smaller CallLevel is stopped 325 } else { 326 // Basic-IDE returns 0 instead of BasicDebugFlags::Continue, so also default=continue 327 nRet = 0; // CallLevel is always > 0 -> no StepPoint 328 } 329 nBreakCallLvl = nRet; // take result 330 } 331 332 SbiInstance::SbiInstance( StarBASIC* p ) 333 : pIosys(new SbiIoSystem) 334 , pDdeCtrl(new SbiDdeControl) 335 , pBasic(p) 336 , meFormatterLangType(LANGUAGE_DONTKNOW) 337 , meFormatterDateOrder(DateOrder::YMD) 338 , nStdDateIdx(0) 339 , nStdTimeIdx(0) 340 , nStdDateTimeIdx(0) 341 , nErr(0) 342 , nErl(0) 343 , bReschedule(true) 344 , bCompatibility(false) 345 , pRun(nullptr) 346 , nCallLvl(0) 347 , nBreakCallLvl(0) 348 { 349 } 350 351 SbiInstance::~SbiInstance() 352 { 353 while( pRun ) 354 { 355 SbiRuntime* p = pRun->pNext; 356 delete pRun; 357 pRun = p; 358 } 359 360 try 361 { 362 int nSize = ComponentVector.size(); 363 if( nSize ) 364 { 365 for( int i = nSize - 1 ; i >= 0 ; --i ) 366 { 367 Reference< XComponent > xDlgComponent = ComponentVector[i]; 368 if( xDlgComponent.is() ) 369 xDlgComponent->dispose(); 370 } 371 } 372 } 373 catch( const Exception& ) 374 { 375 TOOLS_WARN_EXCEPTION("basic", "SbiInstance::~SbiInstance: caught an exception while disposing the components" ); 376 } 377 } 378 379 SbiDllMgr* SbiInstance::GetDllMgr() 380 { 381 if( !pDllMgr ) 382 { 383 pDllMgr.reset(new SbiDllMgr); 384 } 385 return pDllMgr.get(); 386 } 387 388 // #39629 create NumberFormatter with the help of a static method now 389 std::shared_ptr<SvNumberFormatter> const & SbiInstance::GetNumberFormatter() 390 { 391 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 392 SvtSysLocale aSysLocale; 393 DateOrder eDate = aSysLocale.GetLocaleData().getDateOrder(); 394 if( pNumberFormatter ) 395 { 396 if( eLangType != meFormatterLangType || 397 eDate != meFormatterDateOrder ) 398 { 399 pNumberFormatter.reset(); 400 } 401 } 402 meFormatterLangType = eLangType; 403 meFormatterDateOrder = eDate; 404 if( !pNumberFormatter ) 405 { 406 pNumberFormatter = PrepareNumberFormatter( nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx, 407 &meFormatterLangType, &meFormatterDateOrder); 408 } 409 return pNumberFormatter; 410 } 411 412 // #39629 offer NumberFormatter static too 413 std::shared_ptr<SvNumberFormatter> SbiInstance::PrepareNumberFormatter( sal_uInt32 &rnStdDateIdx, 414 sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx, 415 LanguageType const * peFormatterLangType, DateOrder const * peFormatterDateOrder ) 416 { 417 LanguageType eLangType; 418 if( peFormatterLangType ) 419 { 420 eLangType = *peFormatterLangType; 421 } 422 else 423 { 424 eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 425 } 426 DateOrder eDate; 427 if( peFormatterDateOrder ) 428 { 429 eDate = *peFormatterDateOrder; 430 } 431 else 432 { 433 SvtSysLocale aSysLocale; 434 eDate = aSysLocale.GetLocaleData().getDateOrder(); 435 } 436 437 std::shared_ptr<SvNumberFormatter> pNumberFormatter = 438 std::make_shared<SvNumberFormatter>( comphelper::getProcessComponentContext(), eLangType ); 439 440 // Several parser methods pass SvNumberFormatter::IsNumberFormat() a number 441 // format index to parse against. Tell the formatter the proper date 442 // evaluation order, which also determines the date acceptance patterns to 443 // use if a format was passed. NF_EVALDATEFORMAT_FORMAT restricts to the 444 // format's locale's date patterns/order (no init/system locale match 445 // tried) and falls back to NF_EVALDATEFORMAT_INTL if no specific (i.e. 0) 446 // (or an unknown) format index was passed. 447 pNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT); 448 449 sal_Int32 nCheckPos = 0; 450 SvNumFormatType nType; 451 rnStdTimeIdx = pNumberFormatter->GetStandardFormat( SvNumFormatType::TIME, eLangType ); 452 453 // the formatter's standard templates have only got a two-digit date 454 // -> registering an own format 455 456 // HACK, because the numberformatter doesn't swap the place holders 457 // for month, day and year according to the system setting. 458 // Problem: Print Year(Date) under engl. BS 459 // also have a look at: basic/source/sbx/sbxdate.cxx 460 461 OUString aDateStr; 462 switch( eDate ) 463 { 464 default: 465 case DateOrder::MDY: aDateStr = "MM/DD/YYYY"; break; 466 case DateOrder::DMY: aDateStr = "DD/MM/YYYY"; break; 467 case DateOrder::YMD: aDateStr = "YYYY/MM/DD"; break; 468 } 469 OUString aStr( aDateStr ); // PutandConvertEntry() modifies string! 470 pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, 471 rnStdDateIdx, LANGUAGE_ENGLISH_US, eLangType, true); 472 nCheckPos = 0; 473 aDateStr += " HH:MM:SS"; 474 aStr = aDateStr; 475 pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, 476 rnStdDateTimeIdx, LANGUAGE_ENGLISH_US, eLangType, true); 477 return pNumberFormatter; 478 } 479 480 481 // Let engine run. If Flags == BasicDebugFlags::Continue, take Flags over 482 483 void SbiInstance::Stop() 484 { 485 for( SbiRuntime* p = pRun; p; p = p->pNext ) 486 { 487 p->Stop(); 488 } 489 } 490 491 // Allows Basic IDE to set watch mode to suppress errors 492 static bool bWatchMode = false; 493 494 void setBasicWatchMode( bool bOn ) 495 { 496 bWatchMode = bOn; 497 } 498 499 void SbiInstance::Error( ErrCode n ) 500 { 501 Error( n, OUString() ); 502 } 503 504 void SbiInstance::Error( ErrCode n, const OUString& rMsg ) 505 { 506 if( !bWatchMode ) 507 { 508 aErrorMsg = rMsg; 509 pRun->Error( n ); 510 } 511 } 512 513 void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const OUString& rMsg ) 514 { 515 if( !bWatchMode ) 516 { 517 ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); 518 if ( !n ) 519 { 520 n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors 521 } 522 aErrorMsg = rMsg; 523 SbiRuntime::translateErrorToVba( n, aErrorMsg ); 524 525 pRun->Error( ERRCODE_BASIC_COMPAT, true/*bVBATranslationAlreadyDone*/ ); 526 } 527 } 528 529 void SbiInstance::setErrorVB( sal_Int32 nVBNumber ) 530 { 531 ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); 532 if( !n ) 533 { 534 n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors 535 } 536 aErrorMsg = OUString(); 537 SbiRuntime::translateErrorToVba( n, aErrorMsg ); 538 539 nErr = n; 540 } 541 542 543 void SbiInstance::FatalError( ErrCode n ) 544 { 545 pRun->FatalError( n ); 546 } 547 548 void SbiInstance::FatalError( ErrCode _errCode, const OUString& _details ) 549 { 550 pRun->FatalError( _errCode, _details ); 551 } 552 553 void SbiInstance::Abort() 554 { 555 StarBASIC* pErrBasic = GetCurrentBasic( pBasic ); 556 pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 ); 557 StarBASIC::Stop(); 558 } 559 560 // can be unequal to pRTBasic 561 StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic ) 562 { 563 StarBASIC* pCurBasic = pRTBasic; 564 SbModule* pActiveModule = StarBASIC::GetActiveModule(); 565 if( pActiveModule ) 566 { 567 SbxObject* pParent = pActiveModule->GetParent(); 568 if (StarBASIC *pBasic = dynamic_cast<StarBASIC*>(pParent)) 569 pCurBasic = pBasic; 570 } 571 return pCurBasic; 572 } 573 574 SbModule* SbiInstance::GetActiveModule() 575 { 576 if( pRun ) 577 { 578 return pRun->GetModule(); 579 } 580 else 581 { 582 return nullptr; 583 } 584 } 585 586 SbMethod* SbiInstance::GetCaller( sal_uInt16 nLevel ) 587 { 588 SbiRuntime* p = pRun; 589 while( nLevel-- && p ) 590 { 591 p = p->pNext; 592 } 593 return p ? p->GetCaller() : nullptr; 594 } 595 596 // SbiInstance 597 598 // Attention: pMeth can also be NULL (on a call of the init-code) 599 600 SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, sal_uInt32 nStart ) 601 : rBasic( *static_cast<StarBASIC*>(pm->pParent) ), pInst( GetSbData()->pInst ), 602 pMod( pm ), pMeth( pe ), pImg( pMod->pImage.get() ), mpExtCaller(nullptr), m_nLastTime(0) 603 { 604 nFlags = pe ? pe->GetDebugFlags() : BasicDebugFlags::NONE; 605 pIosys = pInst->GetIoSystem(); 606 pForStk = nullptr; 607 pError = nullptr; 608 pErrCode = 609 pErrStmnt = 610 pRestart = nullptr; 611 pNext = nullptr; 612 pCode = 613 pStmnt = pImg->GetCode() + nStart; 614 bRun = 615 bError = true; 616 bInError = false; 617 bBlocked = false; 618 nLine = 0; 619 nCol1 = 0; 620 nCol2 = 0; 621 nExprLvl = 0; 622 nArgc = 0; 623 nError = ERRCODE_NONE; 624 nForLvl = 0; 625 nOps = 0; 626 refExprStk = new SbxArray; 627 SetVBAEnabled( pMod->IsVBACompat() ); 628 SetParameters( pe ? pe->GetParameters() : nullptr ); 629 } 630 631 SbiRuntime::~SbiRuntime() 632 { 633 ClearArgvStack(); 634 ClearForStack(); 635 } 636 637 void SbiRuntime::SetVBAEnabled(bool bEnabled ) 638 { 639 bVBAEnabled = bEnabled; 640 if ( bVBAEnabled ) 641 { 642 if ( pMeth ) 643 { 644 mpExtCaller = pMeth->mCaller; 645 } 646 } 647 else 648 { 649 mpExtCaller = nullptr; 650 } 651 } 652 653 // tdf#79426, tdf#125180 - adds the information about a missing parameter 654 void SbiRuntime::SetIsMissing( SbxVariable* pVar ) 655 { 656 SbxInfo* pInfo = pVar->GetInfo() ? pVar->GetInfo() : new SbxInfo(); 657 pInfo->AddParam( pVar->GetName(), SbxMISSING, pVar->GetFlags() ); 658 pVar->SetInfo( pInfo ); 659 } 660 661 // tdf#79426, tdf#125180 - checks if a variable contains the information about a missing parameter 662 bool SbiRuntime::IsMissing( SbxVariable* pVar, sal_uInt16 nIdx ) 663 { 664 return pVar->GetInfo() && pVar->GetInfo()->GetParam( nIdx ) && pVar->GetInfo()->GetParam( nIdx )->eType & SbxMISSING; 665 } 666 667 // Construction of the parameter list. All ByRef-parameters are directly 668 // taken over; copies of ByVal-parameters are created. If a particular 669 // data type is requested, it is converted. 670 671 void SbiRuntime::SetParameters( SbxArray* pParams ) 672 { 673 refParams = new SbxArray; 674 // for the return value 675 refParams->Put(pMeth, 0); 676 677 SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : nullptr; 678 sal_uInt32 nParamCount = pParams ? pParams->Count() : 1; 679 assert(nParamCount <= std::numeric_limits<sal_uInt16>::max()); 680 if( nParamCount > 1 ) 681 { 682 for( sal_uInt32 i = 1 ; i < nParamCount ; i++ ) 683 { 684 const SbxParamInfo* p = pInfo ? pInfo->GetParam( sal::static_int_cast<sal_uInt16>(i) ) : nullptr; 685 686 // #111897 ParamArray 687 if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) 688 { 689 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); 690 sal_uInt32 nParamArrayParamCount = nParamCount - i; 691 pArray->unoAddDim(0, nParamArrayParamCount - 1); 692 for (sal_uInt32 j = i; j < nParamCount ; ++j) 693 { 694 SbxVariable* v = pParams->Get(j); 695 sal_Int32 aDimIndex[1]; 696 aDimIndex[0] = j - i; 697 pArray->Put(v, aDimIndex); 698 } 699 SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); 700 pArrayVar->SetFlag( SbxFlagBits::ReadWrite ); 701 pArrayVar->PutObject( pArray ); 702 refParams->Put(pArrayVar, i); 703 704 // Block ParamArray for missing parameter 705 pInfo = nullptr; 706 break; 707 } 708 709 SbxVariable* v = pParams->Get(i); 710 // methods are always byval! 711 bool bByVal = dynamic_cast<const SbxMethod *>(v) != nullptr; 712 SbxDataType t = v->GetType(); 713 bool bTargetTypeIsArray = false; 714 if( p ) 715 { 716 bByVal |= ( p->eType & SbxBYREF ) == 0; 717 // tdf#79426, tdf#125180 - don't convert missing arguments to the requested parameter type 718 if ( !IsMissing( v, 1 ) ) 719 { 720 t = static_cast<SbxDataType>( p->eType & 0x0FFF ); 721 } 722 723 if( !bByVal && t != SbxVARIANT && 724 (!v->IsFixed() || static_cast<SbxDataType>(v->GetType() & 0x0FFF ) != t) ) 725 { 726 bByVal = true; 727 } 728 729 bTargetTypeIsArray = (p->nUserData & PARAM_INFO_WITHBRACKETS) != 0; 730 } 731 if( bByVal ) 732 { 733 // tdf#79426, tdf#125180 - don't convert missing arguments to the requested parameter type 734 if( bTargetTypeIsArray && !IsMissing( v, 1 ) ) 735 { 736 t = SbxOBJECT; 737 } 738 SbxVariable* v2 = new SbxVariable( t ); 739 v2->SetFlag( SbxFlagBits::ReadWrite ); 740 // tdf#79426, tdf#125180 - if parameter was missing, readd additional information about a missing parameter 741 if ( IsMissing( v, 1 ) ) 742 { 743 SetIsMissing( v2 ); 744 } 745 *v2 = *v; 746 refParams->Put(v2, i); 747 } 748 else 749 { 750 // tdf#79426, tdf#125180 - don't convert missing arguments to the requested parameter type 751 if( t != SbxVARIANT && !IsMissing( v, 1 ) && t != ( v->GetType() & 0x0FFF ) ) 752 { 753 if( p && (p->eType & SbxARRAY) ) 754 { 755 Error( ERRCODE_BASIC_CONVERSION ); 756 } 757 else 758 { 759 v->Convert( t ); 760 } 761 } 762 refParams->Put(v, i); 763 } 764 if( p ) 765 { 766 refParams->PutAlias(p->aName, i); 767 } 768 } 769 } 770 771 // ParamArray for missing parameter 772 if( !pInfo ) 773 return; 774 775 // #111897 Check first missing parameter for ParamArray 776 const SbxParamInfo* p = pInfo->GetParam(sal::static_int_cast<sal_uInt16>(nParamCount)); 777 if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) 778 { 779 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); 780 pArray->unoAddDim(0, -1); 781 SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); 782 pArrayVar->SetFlag( SbxFlagBits::ReadWrite ); 783 pArrayVar->PutObject( pArray ); 784 refParams->Put(pArrayVar, nParamCount); 785 } 786 } 787 788 789 // execute a P-Code 790 791 bool SbiRuntime::Step() 792 { 793 if( bRun ) 794 { 795 // in any case check casually! 796 if( !( ++nOps & 0xF ) && pInst->IsReschedule() ) 797 { 798 sal_uInt32 nTime = osl_getGlobalTimer(); 799 if (nTime - m_nLastTime > 5 ) // 20 ms 800 { 801 Application::Reschedule(); 802 m_nLastTime = nTime; 803 } 804 } 805 806 // #i48868 blocked by next call level? 807 while( bBlocked ) 808 { 809 if( pInst->IsReschedule() ) 810 { 811 Application::Reschedule(); 812 } 813 } 814 815 SbiOpcode eOp = static_cast<SbiOpcode>( *pCode++ ); 816 sal_uInt32 nOp1; 817 if (eOp <= SbiOpcode::SbOP0_END) 818 { 819 (this->*( aStep0[ int(eOp) ] ) )(); 820 } 821 else if (eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END) 822 { 823 nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; 824 825 (this->*( aStep1[ int(eOp) - int(SbiOpcode::SbOP1_START) ] ) )( nOp1 ); 826 } 827 else if (eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END) 828 { 829 nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; 830 sal_uInt32 nOp2 = *pCode++; nOp2 |= *pCode++ << 8; nOp2 |= *pCode++ << 16; nOp2 |= *pCode++ << 24; 831 (this->*( aStep2[ int(eOp) - int(SbiOpcode::SbOP2_START) ] ) )( nOp1, nOp2 ); 832 } 833 else 834 { 835 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 836 } 837 838 ErrCode nErrCode = SbxBase::GetError(); 839 Error( nErrCode.IgnoreWarning() ); 840 841 // from 13.2.1997, new error handling: 842 // ATTENTION: nError can be set already even if !nErrCode 843 // since nError can now also be set from other RT-instances 844 845 if( nError ) 846 { 847 SbxBase::ResetError(); 848 } 849 850 // from 15.3.96: display errors only if BASIC is still active 851 // (especially not after compiler errors at the runtime) 852 if( nError && bRun ) 853 { 854 ErrCode err = nError; 855 ClearExprStack(); 856 nError = ERRCODE_NONE; 857 pInst->nErr = err; 858 pInst->nErl = nLine; 859 pErrCode = pCode; 860 pErrStmnt = pStmnt; 861 // An error occurred in an error handler 862 // force parent handler ( if there is one ) 863 // to handle the error 864 bool bLetParentHandleThis = false; 865 866 // in the error handler? so std-error 867 if ( !bInError ) 868 { 869 bInError = true; 870 871 if( !bError ) // On Error Resume Next 872 { 873 StepRESUME( 1 ); 874 } 875 else if( pError ) // On Error Goto ... 876 { 877 pCode = pError; 878 } 879 else 880 { 881 bLetParentHandleThis = true; 882 } 883 } 884 else 885 { 886 bLetParentHandleThis = true; 887 pError = nullptr; //terminate the handler 888 } 889 if ( bLetParentHandleThis ) 890 { 891 // from 13.2.1997, new error handling: 892 // consider superior error handlers 893 894 // there's no error handler -> find one farther above 895 SbiRuntime* pRtErrHdl = nullptr; 896 SbiRuntime* pRt = this; 897 while( (pRt = pRt->pNext) != nullptr ) 898 { 899 if( !pRt->bError || pRt->pError != nullptr ) 900 { 901 pRtErrHdl = pRt; 902 break; 903 } 904 } 905 906 907 if( pRtErrHdl ) 908 { 909 // manipulate all the RTs that are below in the call-stack 910 pRt = this; 911 do 912 { 913 pRt->nError = err; 914 if( pRt != pRtErrHdl ) 915 { 916 pRt->bRun = false; 917 } 918 else 919 { 920 break; 921 } 922 pRt = pRt->pNext; 923 } 924 while( pRt ); 925 } 926 // no error-hdl found -> old behaviour 927 else 928 { 929 pInst->Abort(); 930 } 931 } 932 } 933 } 934 return bRun; 935 } 936 937 void SbiRuntime::Error( ErrCode n, bool bVBATranslationAlreadyDone ) 938 { 939 if( !n ) 940 return; 941 942 nError = n; 943 if( !isVBAEnabled() || bVBATranslationAlreadyDone ) 944 return; 945 946 OUString aMsg = pInst->GetErrorMsg(); 947 sal_Int32 nVBAErrorNumber = translateErrorToVba( nError, aMsg ); 948 SbxVariable* pSbxErrObjVar = SbxErrObject::getErrObject().get(); 949 SbxErrObject* pGlobErr = static_cast< SbxErrObject* >( pSbxErrObjVar ); 950 if( pGlobErr != nullptr ) 951 { 952 pGlobErr->setNumberAndDescription( nVBAErrorNumber, aMsg ); 953 } 954 pInst->aErrorMsg = aMsg; 955 nError = ERRCODE_BASIC_COMPAT; 956 } 957 958 void SbiRuntime::Error( ErrCode _errCode, const OUString& _details ) 959 { 960 if ( !_errCode ) 961 return; 962 963 // Not correct for class module usage, remove for now 964 //OSL_WARN_IF( pInst->pRun != this, "basic", "SbiRuntime::Error: can't propagate the error message details!" ); 965 if ( pInst->pRun == this ) 966 { 967 pInst->Error( _errCode, _details ); 968 //OSL_WARN_IF( nError != _errCode, "basic", "SbiRuntime::Error: the instance is expected to propagate the error code back to me!" ); 969 } 970 else 971 { 972 nError = _errCode; 973 } 974 } 975 976 void SbiRuntime::FatalError( ErrCode n ) 977 { 978 StepSTDERROR(); 979 Error( n ); 980 } 981 982 void SbiRuntime::FatalError( ErrCode _errCode, const OUString& _details ) 983 { 984 StepSTDERROR(); 985 Error( _errCode, _details ); 986 } 987 988 sal_Int32 SbiRuntime::translateErrorToVba( ErrCode nError, OUString& rMsg ) 989 { 990 // If a message is defined use that ( in preference to 991 // the defined one for the error ) NB #TODO 992 // if there is an error defined it more than likely 993 // is not the one you want ( some are the same though ) 994 // we really need a new vba compatible error list 995 if ( rMsg.isEmpty() ) 996 { 997 StarBASIC::MakeErrorText( nError, rMsg ); 998 rMsg = StarBASIC::GetErrorText(); 999 if ( rMsg.isEmpty() ) // no message for err no, need localized resource here 1000 { 1001 rMsg = "Internal Object Error:"; 1002 } 1003 } 1004 // no num? most likely then it *is* really a vba err 1005 sal_uInt16 nVBErrorCode = StarBASIC::GetVBErrorCode( nError ); 1006 sal_Int32 nVBAErrorNumber = ( nVBErrorCode == 0 ) ? sal_uInt32(nError) : nVBErrorCode; 1007 return nVBAErrorNumber; 1008 } 1009 1010 // Stacks 1011 1012 // The expression-stack is available for the continuous evaluation 1013 // of expressions. 1014 1015 void SbiRuntime::PushVar( SbxVariable* pVar ) 1016 { 1017 if( pVar ) 1018 { 1019 refExprStk->Put(pVar, nExprLvl++); 1020 } 1021 } 1022 1023 SbxVariableRef SbiRuntime::PopVar() 1024 { 1025 #ifdef DBG_UTIL 1026 if( !nExprLvl ) 1027 { 1028 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 1029 return new SbxVariable; 1030 } 1031 #endif 1032 SbxVariableRef xVar = refExprStk->Get(--nExprLvl); 1033 SAL_INFO_IF( xVar->GetName() == "Cells", "basic", "PopVar: Name equals 'Cells'" ); 1034 // methods hold themselves in parameter 0 1035 if( dynamic_cast<const SbxMethod *>(xVar.get()) != nullptr ) 1036 { 1037 xVar->SetParameters(nullptr); 1038 } 1039 return xVar; 1040 } 1041 1042 void SbiRuntime::ClearExprStack() 1043 { 1044 // Attention: Clear() doesn't suffice as methods must be deleted 1045 while ( nExprLvl ) 1046 { 1047 PopVar(); 1048 } 1049 refExprStk->Clear(); 1050 } 1051 1052 // Take variable from the expression-stack without removing it 1053 // n counts from 0 1054 1055 SbxVariable* SbiRuntime::GetTOS() 1056 { 1057 short n = nExprLvl - 1; 1058 #ifdef DBG_UTIL 1059 if( n < 0 ) 1060 { 1061 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 1062 return new SbxVariable; 1063 } 1064 #endif 1065 return refExprStk->Get(static_cast<sal_uInt32>(n)); 1066 } 1067 1068 1069 void SbiRuntime::TOSMakeTemp() 1070 { 1071 SbxVariable* p = refExprStk->Get(nExprLvl - 1); 1072 if ( p->GetType() == SbxEMPTY ) 1073 { 1074 p->Broadcast( SfxHintId::BasicDataWanted ); 1075 } 1076 1077 SbxVariable* pDflt = nullptr; 1078 if ( bVBAEnabled && ( p->GetType() == SbxOBJECT || p->GetType() == SbxVARIANT ) && ((pDflt = getDefaultProp(p)) != nullptr) ) 1079 { 1080 pDflt->Broadcast( SfxHintId::BasicDataWanted ); 1081 // replacing new p on stack causes object pointed by 1082 // pDft->pParent to be deleted, when p2->Compute() is 1083 // called below pParent is accessed (but it's deleted) 1084 // so set it to NULL now 1085 pDflt->SetParent( nullptr ); 1086 p = new SbxVariable( *pDflt ); 1087 p->SetFlag( SbxFlagBits::ReadWrite ); 1088 refExprStk->Put(p, nExprLvl - 1); 1089 } 1090 else if( p->GetRefCount() != 1 ) 1091 { 1092 SbxVariable* pNew = new SbxVariable( *p ); 1093 pNew->SetFlag( SbxFlagBits::ReadWrite ); 1094 refExprStk->Put(pNew, nExprLvl - 1); 1095 } 1096 } 1097 1098 // the GOSUB-stack collects return-addresses for GOSUBs 1099 void SbiRuntime::PushGosub( const sal_uInt8* pc ) 1100 { 1101 if( pGosubStk.size() >= MAXRECURSION ) 1102 { 1103 StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW ); 1104 } 1105 pGosubStk.emplace_back(pc, nForLvl); 1106 } 1107 1108 void SbiRuntime::PopGosub() 1109 { 1110 if( pGosubStk.empty() ) 1111 { 1112 Error( ERRCODE_BASIC_NO_GOSUB ); 1113 } 1114 else 1115 { 1116 pCode = pGosubStk.back().pCode; 1117 pGosubStk.pop_back(); 1118 } 1119 } 1120 1121 // the Argv-stack collects current argument-vectors 1122 1123 void SbiRuntime::PushArgv() 1124 { 1125 pArgvStk.emplace_back(refArgv, nArgc); 1126 nArgc = 1; 1127 refArgv.clear(); 1128 } 1129 1130 void SbiRuntime::PopArgv() 1131 { 1132 if( !pArgvStk.empty() ) 1133 { 1134 refArgv = pArgvStk.back().refArgv; 1135 nArgc = pArgvStk.back().nArgc; 1136 pArgvStk.pop_back(); 1137 } 1138 } 1139 1140 1141 void SbiRuntime::ClearArgvStack() 1142 { 1143 while( !pArgvStk.empty() ) 1144 { 1145 PopArgv(); 1146 } 1147 } 1148 1149 // Push of the for-stack. The stack has increment, end, begin and variable. 1150 // After the creation of the stack-element the stack's empty. 1151 1152 void SbiRuntime::PushFor() 1153 { 1154 SbiForStack* p = new SbiForStack; 1155 p->eForType = ForType::To; 1156 p->pNext = pForStk; 1157 pForStk = p; 1158 1159 p->refInc = PopVar(); 1160 p->refEnd = PopVar(); 1161 SbxVariableRef xBgn = PopVar(); 1162 p->refVar = PopVar(); 1163 // tdf#85371 - grant explicitly write access to the index variable 1164 // since it could be the name of a method itself used in the next statement. 1165 ScopedWritableGuard aGuard(p->refVar, p->refVar.get() == pMeth); 1166 *(p->refVar) = *xBgn; 1167 nForLvl++; 1168 } 1169 1170 void SbiRuntime::PushForEach() 1171 { 1172 SbiForStack* p = new SbiForStack; 1173 // Set default value in case of error which is ignored in Resume Next 1174 p->eForType = ForType::EachArray; 1175 p->pNext = pForStk; 1176 pForStk = p; 1177 1178 SbxVariableRef xObjVar = PopVar(); 1179 SbxBase* pObj = xObjVar && xObjVar->GetFullType() == SbxOBJECT ? xObjVar->GetObject() : nullptr; 1180 1181 if (SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(pObj)) 1182 { 1183 p->refEnd = reinterpret_cast<SbxVariable*>(pArray); 1184 1185 sal_Int32 nDims = pArray->GetDims(); 1186 p->pArrayLowerBounds.reset( new sal_Int32[nDims] ); 1187 p->pArrayUpperBounds.reset( new sal_Int32[nDims] ); 1188 p->pArrayCurIndices.reset( new sal_Int32[nDims] ); 1189 sal_Int32 lBound, uBound; 1190 for( sal_Int32 i = 0 ; i < nDims ; i++ ) 1191 { 1192 pArray->GetDim(i + 1, lBound, uBound); 1193 p->pArrayCurIndices[i] = p->pArrayLowerBounds[i] = lBound; 1194 p->pArrayUpperBounds[i] = uBound; 1195 } 1196 } 1197 else if (BasicCollection* pCollection = dynamic_cast<BasicCollection*>(pObj)) 1198 { 1199 p->eForType = ForType::EachCollection; 1200 p->refEnd = pCollection; 1201 p->nCurCollectionIndex = 0; 1202 } 1203 else if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj)) 1204 { 1205 // XEnumerationAccess? 1206 Any aAny = pUnoObj->getUnoAny(); 1207 Reference< XEnumerationAccess > xEnumerationAccess; 1208 if( aAny >>= xEnumerationAccess ) 1209 { 1210 p->xEnumeration = xEnumerationAccess->createEnumeration(); 1211 p->eForType = ForType::EachXEnumeration; 1212 } 1213 else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() ) 1214 { 1215 uno::Reference< script::XInvocation > xInvocation; 1216 if ( ( aAny >>= xInvocation ) && xInvocation.is() ) 1217 { 1218 try 1219 { 1220 p->xEnumeration = new ComEnumerationWrapper( xInvocation ); 1221 p->eForType = ForType::EachXEnumeration; 1222 } 1223 catch(const uno::Exception& ) 1224 {} 1225 } 1226 } 1227 } 1228 1229 // Container variable 1230 p->refVar = PopVar(); 1231 nForLvl++; 1232 } 1233 1234 1235 void SbiRuntime::PopFor() 1236 { 1237 if( pForStk ) 1238 { 1239 SbiForStack* p = pForStk; 1240 pForStk = p->pNext; 1241 delete p; 1242 nForLvl--; 1243 } 1244 } 1245 1246 1247 void SbiRuntime::ClearForStack() 1248 { 1249 while( pForStk ) 1250 { 1251 PopFor(); 1252 } 1253 } 1254 1255 SbiForStack* SbiRuntime::FindForStackItemForCollection( class BasicCollection const * pCollection ) 1256 { 1257 for (SbiForStack *p = pForStk; p; p = p->pNext) 1258 { 1259 SbxVariable* pVar = p->refEnd.is() ? p->refEnd.get() : nullptr; 1260 if( p->eForType == ForType::EachCollection 1261 && pVar != nullptr 1262 && dynamic_cast<BasicCollection*>( pVar) == pCollection ) 1263 { 1264 return p; 1265 } 1266 } 1267 1268 return nullptr; 1269 } 1270 1271 1272 // DLL-calls 1273 1274 void SbiRuntime::DllCall 1275 ( std::u16string_view aFuncName, 1276 std::u16string_view aDLLName, 1277 SbxArray* pArgs, // parameter (from index 1, can be NULL) 1278 SbxDataType eResType, // return value 1279 bool bCDecl ) // true: according to C-conventions 1280 { 1281 // NOT YET IMPLEMENTED 1282 1283 SbxVariable* pRes = new SbxVariable( eResType ); 1284 SbiDllMgr* pDllMgr = pInst->GetDllMgr(); 1285 ErrCode nErr = pDllMgr->Call( aFuncName, aDLLName, pArgs, *pRes, bCDecl ); 1286 if( nErr ) 1287 { 1288 Error( nErr ); 1289 } 1290 PushVar( pRes ); 1291 } 1292 1293 bool SbiRuntime::IsImageFlag( SbiImageFlags n ) const 1294 { 1295 return pImg->IsFlag( n ); 1296 } 1297 1298 sal_uInt16 SbiRuntime::GetBase() const 1299 { 1300 return pImg->GetBase(); 1301 } 1302 1303 void SbiRuntime::StepNOP() 1304 {} 1305 1306 void SbiRuntime::StepArith( SbxOperator eOp ) 1307 { 1308 SbxVariableRef p1 = PopVar(); 1309 TOSMakeTemp(); 1310 SbxVariable* p2 = GetTOS(); 1311 1312 p2->ResetFlag( SbxFlagBits::Fixed ); 1313 p2->Compute( eOp, *p1 ); 1314 1315 checkArithmeticOverflow( p2 ); 1316 } 1317 1318 void SbiRuntime::StepUnary( SbxOperator eOp ) 1319 { 1320 TOSMakeTemp(); 1321 SbxVariable* p = GetTOS(); 1322 p->Compute( eOp, *p ); 1323 } 1324 1325 void SbiRuntime::StepCompare( SbxOperator eOp ) 1326 { 1327 SbxVariableRef p1 = PopVar(); 1328 SbxVariableRef p2 = PopVar(); 1329 1330 // Make sure objects with default params have 1331 // values ( and type ) set as appropriate 1332 SbxDataType p1Type = p1->GetType(); 1333 SbxDataType p2Type = p2->GetType(); 1334 if ( p1Type == SbxEMPTY ) 1335 { 1336 p1->Broadcast( SfxHintId::BasicDataWanted ); 1337 p1Type = p1->GetType(); 1338 } 1339 if ( p2Type == SbxEMPTY ) 1340 { 1341 p2->Broadcast( SfxHintId::BasicDataWanted ); 1342 p2Type = p2->GetType(); 1343 } 1344 if ( p1Type == p2Type ) 1345 { 1346 // if both sides are an object and have default props 1347 // then we need to use the default props 1348 // we don't need to worry if only one side ( lhs, rhs ) is an 1349 // object ( object side will get coerced to correct type in 1350 // Compare ) 1351 if ( p1Type == SbxOBJECT ) 1352 { 1353 SbxVariable* pDflt = getDefaultProp( p1.get() ); 1354 if ( pDflt ) 1355 { 1356 p1 = pDflt; 1357 p1->Broadcast( SfxHintId::BasicDataWanted ); 1358 } 1359 pDflt = getDefaultProp( p2.get() ); 1360 if ( pDflt ) 1361 { 1362 p2 = pDflt; 1363 p2->Broadcast( SfxHintId::BasicDataWanted ); 1364 } 1365 } 1366 1367 } 1368 static SbxVariable* pTRUE = nullptr; 1369 static SbxVariable* pFALSE = nullptr; 1370 // why do this on non-windows ? 1371 // why do this at all ? 1372 // I dumbly follow the pattern :-/ 1373 if ( bVBAEnabled && ( p1->IsNull() || p2->IsNull() ) ) 1374 { 1375 static SbxVariable* pNULL = []() { 1376 SbxVariable* p = new SbxVariable; 1377 p->PutNull(); 1378 p->AddFirstRef(); 1379 return p; 1380 }(); 1381 PushVar( pNULL ); 1382 } 1383 else if( p2->Compare( eOp, *p1 ) ) 1384 { 1385 if( !pTRUE ) 1386 { 1387 pTRUE = new SbxVariable; 1388 pTRUE->PutBool( true ); 1389 pTRUE->AddFirstRef(); 1390 } 1391 PushVar( pTRUE ); 1392 } 1393 else 1394 { 1395 if( !pFALSE ) 1396 { 1397 pFALSE = new SbxVariable; 1398 pFALSE->PutBool( false ); 1399 pFALSE->AddFirstRef(); 1400 } 1401 PushVar( pFALSE ); 1402 } 1403 } 1404 1405 void SbiRuntime::StepEXP() { StepArith( SbxEXP ); } 1406 void SbiRuntime::StepMUL() { StepArith( SbxMUL ); } 1407 void SbiRuntime::StepDIV() { StepArith( SbxDIV ); } 1408 void SbiRuntime::StepIDIV() { StepArith( SbxIDIV ); } 1409 void SbiRuntime::StepMOD() { StepArith( SbxMOD ); } 1410 void SbiRuntime::StepPLUS() { StepArith( SbxPLUS ); } 1411 void SbiRuntime::StepMINUS() { StepArith( SbxMINUS ); } 1412 void SbiRuntime::StepCAT() { StepArith( SbxCAT ); } 1413 void SbiRuntime::StepAND() { StepArith( SbxAND ); } 1414 void SbiRuntime::StepOR() { StepArith( SbxOR ); } 1415 void SbiRuntime::StepXOR() { StepArith( SbxXOR ); } 1416 void SbiRuntime::StepEQV() { StepArith( SbxEQV ); } 1417 void SbiRuntime::StepIMP() { StepArith( SbxIMP ); } 1418 1419 void SbiRuntime::StepNEG() { StepUnary( SbxNEG ); } 1420 void SbiRuntime::StepNOT() { StepUnary( SbxNOT ); } 1421 1422 void SbiRuntime::StepEQ() { StepCompare( SbxEQ ); } 1423 void SbiRuntime::StepNE() { StepCompare( SbxNE ); } 1424 void SbiRuntime::StepLT() { StepCompare( SbxLT ); } 1425 void SbiRuntime::StepGT() { StepCompare( SbxGT ); } 1426 void SbiRuntime::StepLE() { StepCompare( SbxLE ); } 1427 void SbiRuntime::StepGE() { StepCompare( SbxGE ); } 1428 1429 namespace 1430 { 1431 bool NeedEsc(sal_Unicode cCode) 1432 { 1433 if(!rtl::isAscii(cCode)) 1434 { 1435 return false; 1436 } 1437 switch(cCode) 1438 { 1439 case '.': 1440 case '^': 1441 case '$': 1442 case '+': 1443 case '\\': 1444 case '|': 1445 case '{': 1446 case '}': 1447 case '(': 1448 case ')': 1449 return true; 1450 default: 1451 return false; 1452 } 1453 } 1454 1455 OUString VBALikeToRegexp(const OUString &rIn) 1456 { 1457 OUStringBuffer sResult; 1458 const sal_Unicode *start = rIn.getStr(); 1459 const sal_Unicode *end = start + rIn.getLength(); 1460 1461 int seenright = 0; 1462 1463 sResult.append('^'); 1464 1465 while (start < end) 1466 { 1467 switch (*start) 1468 { 1469 case '?': 1470 sResult.append('.'); 1471 start++; 1472 break; 1473 case '*': 1474 sResult.append(".*"); 1475 start++; 1476 break; 1477 case '#': 1478 sResult.append("[0-9]"); 1479 start++; 1480 break; 1481 case ']': 1482 sResult.append('\\'); 1483 sResult.append(*start++); 1484 break; 1485 case '[': 1486 sResult.append(*start++); 1487 seenright = 0; 1488 while (start < end && !seenright) 1489 { 1490 switch (*start) 1491 { 1492 case '[': 1493 case '?': 1494 case '*': 1495 sResult.append('\\'); 1496 sResult.append(*start); 1497 break; 1498 case ']': 1499 sResult.append(*start); 1500 seenright = 1; 1501 break; 1502 case '!': 1503 sResult.append('^'); 1504 break; 1505 default: 1506 if (NeedEsc(*start)) 1507 { 1508 sResult.append('\\'); 1509 } 1510 sResult.append(*start); 1511 break; 1512 } 1513 start++; 1514 } 1515 break; 1516 default: 1517 if (NeedEsc(*start)) 1518 { 1519 sResult.append('\\'); 1520 } 1521 sResult.append(*start++); 1522 } 1523 } 1524 1525 sResult.append('$'); 1526 1527 return sResult.makeStringAndClear(); 1528 } 1529 } 1530 1531 void SbiRuntime::StepLIKE() 1532 { 1533 SbxVariableRef refVar1 = PopVar(); 1534 SbxVariableRef refVar2 = PopVar(); 1535 1536 OUString pattern = VBALikeToRegexp(refVar1->GetOUString()); 1537 OUString value = refVar2->GetOUString(); 1538 1539 i18nutil::SearchOptions2 aSearchOpt; 1540 1541 aSearchOpt.AlgorithmType2 = css::util::SearchAlgorithms2::REGEXP; 1542 1543 aSearchOpt.Locale = Application::GetSettings().GetLanguageTag().getLocale(); 1544 aSearchOpt.searchString = pattern; 1545 1546 bool bTextMode(true); 1547 bool bCompatibility = ( GetSbData()->pInst && GetSbData()->pInst->IsCompatibility() ); 1548 if( bCompatibility ) 1549 { 1550 bTextMode = IsImageFlag( SbiImageFlags::COMPARETEXT ); 1551 } 1552 if( bTextMode ) 1553 { 1554 aSearchOpt.transliterateFlags |= TransliterationFlags::IGNORE_CASE; 1555 } 1556 SbxVariable* pRes = new SbxVariable; 1557 utl::TextSearch aSearch( aSearchOpt); 1558 sal_Int32 nStart=0, nEnd=value.getLength(); 1559 bool bRes = aSearch.SearchForward(value, &nStart, &nEnd); 1560 pRes->PutBool( bRes ); 1561 1562 PushVar( pRes ); 1563 } 1564 1565 // TOS and TOS-1 are both object variables and contain the same pointer 1566 1567 void SbiRuntime::StepIS() 1568 { 1569 SbxVariableRef refVar1 = PopVar(); 1570 SbxVariableRef refVar2 = PopVar(); 1571 1572 SbxDataType eType1 = refVar1->GetType(); 1573 SbxDataType eType2 = refVar2->GetType(); 1574 if ( eType1 == SbxEMPTY ) 1575 { 1576 refVar1->Broadcast( SfxHintId::BasicDataWanted ); 1577 eType1 = refVar1->GetType(); 1578 } 1579 if ( eType2 == SbxEMPTY ) 1580 { 1581 refVar2->Broadcast( SfxHintId::BasicDataWanted ); 1582 eType2 = refVar2->GetType(); 1583 } 1584 1585 bool bRes = ( eType1 == SbxOBJECT && eType2 == SbxOBJECT ); 1586 if ( bVBAEnabled && !bRes ) 1587 { 1588 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1589 } 1590 bRes = ( bRes && refVar1->GetObject() == refVar2->GetObject() ); 1591 SbxVariable* pRes = new SbxVariable; 1592 pRes->PutBool( bRes ); 1593 PushVar( pRes ); 1594 } 1595 1596 // update the value of TOS 1597 1598 void SbiRuntime::StepGET() 1599 { 1600 SbxVariable* p = GetTOS(); 1601 p->Broadcast( SfxHintId::BasicDataWanted ); 1602 } 1603 1604 // #67607 copy Uno-Structs 1605 static bool checkUnoStructCopy( bool bVBA, SbxVariableRef const & refVal, SbxVariableRef const & refVar ) 1606 { 1607 SbxDataType eVarType = refVar->GetType(); 1608 SbxDataType eValType = refVal->GetType(); 1609 1610 if ( ( bVBA && ( eVarType == SbxEMPTY ) ) || !refVar->CanWrite() ) 1611 return false; 1612 1613 if ( eValType != SbxOBJECT ) 1614 return false; 1615 // we seem to be duplicating parts of SbxValue=operator, maybe we should just move this to 1616 // there :-/ not sure if for every '=' we would want struct handling 1617 if( eVarType != SbxOBJECT ) 1618 { 1619 if ( refVar->IsFixed() ) 1620 return false; 1621 } 1622 // #115826: Exclude ProcedureProperties to avoid call to Property Get procedure 1623 else if( dynamic_cast<const SbProcedureProperty*>( refVar.get() ) != nullptr ) 1624 return false; 1625 1626 SbxObjectRef xValObj = static_cast<SbxObject*>(refVal->GetObject()); 1627 if( !xValObj.is() || dynamic_cast<const SbUnoAnyObject*>( xValObj.get() ) != nullptr ) 1628 return false; 1629 1630 SbUnoObject* pUnoVal = dynamic_cast<SbUnoObject*>( xValObj.get() ); 1631 SbUnoStructRefObject* pUnoStructVal = dynamic_cast<SbUnoStructRefObject*>( xValObj.get() ); 1632 Any aAny; 1633 // make doubly sure value is either a Uno object or 1634 // a uno struct 1635 if ( pUnoVal || pUnoStructVal ) 1636 aAny = pUnoVal ? pUnoVal->getUnoAny() : pUnoStructVal->getUnoAny(); 1637 else 1638 return false; 1639 if ( aAny.getValueType().getTypeClass() == TypeClass_STRUCT ) 1640 { 1641 refVar->SetType( SbxOBJECT ); 1642 ErrCode eOldErr = SbxBase::GetError(); 1643 // There are some circumstances when calling GetObject 1644 // will trigger an error, we need to squash those here. 1645 // Alternatively it is possible that the same scenario 1646 // could overwrite and existing error. Lets prevent that 1647 SbxObjectRef xVarObj = static_cast<SbxObject*>(refVar->GetObject()); 1648 if ( eOldErr != ERRCODE_NONE ) 1649 SbxBase::SetError( eOldErr ); 1650 else 1651 SbxBase::ResetError(); 1652 1653 SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( xVarObj.get() ); 1654 1655 OUString sClassName = pUnoVal ? pUnoVal->GetClassName() : pUnoStructVal->GetClassName(); 1656 OUString sName = pUnoVal ? pUnoVal->GetName() : pUnoStructVal->GetName(); 1657 1658 if ( pUnoStructObj ) 1659 { 1660 StructRefInfo aInfo = pUnoStructObj->getStructInfo(); 1661 aInfo.setValue( aAny ); 1662 } 1663 else 1664 { 1665 SbUnoObject* pNewUnoObj = new SbUnoObject( sName, aAny ); 1666 // #70324: adopt ClassName 1667 pNewUnoObj->SetClassName( sClassName ); 1668 refVar->PutObject( pNewUnoObj ); 1669 } 1670 return true; 1671 } 1672 return false; 1673 } 1674 1675 1676 // laying down TOS in TOS-1 1677 1678 void SbiRuntime::StepPUT() 1679 { 1680 SbxVariableRef refVal = PopVar(); 1681 SbxVariableRef refVar = PopVar(); 1682 // store on its own method (inside a function)? 1683 bool bFlagsChanged = false; 1684 SbxFlagBits n = SbxFlagBits::NONE; 1685 if( refVar.get() == pMeth ) 1686 { 1687 bFlagsChanged = true; 1688 n = refVar->GetFlags(); 1689 refVar->SetFlag( SbxFlagBits::Write ); 1690 } 1691 1692 // if left side arg is an object or variant and right handside isn't 1693 // either an object or a variant then try and see if a default 1694 // property exists. 1695 // to use e.g. Range{"A1") = 34 1696 // could equate to Range("A1").Value = 34 1697 if ( bVBAEnabled ) 1698 { 1699 // yet more hacking at this, I feel we don't quite have the correct 1700 // heuristics for dealing with obj1 = obj2 ( where obj2 ( and maybe 1701 // obj1 ) has default member/property ) ) It seems that default props 1702 // aren't dealt with if the object is a member of some parent object 1703 bool bObjAssign = false; 1704 if ( refVar->GetType() == SbxEMPTY ) 1705 refVar->Broadcast( SfxHintId::BasicDataWanted ); 1706 if ( refVar->GetType() == SbxOBJECT ) 1707 { 1708 if ( dynamic_cast<const SbxMethod *>(refVar.get()) != nullptr || ! refVar->GetParent() ) 1709 { 1710 SbxVariable* pDflt = getDefaultProp( refVar.get() ); 1711 1712 if ( pDflt ) 1713 refVar = pDflt; 1714 } 1715 else 1716 bObjAssign = true; 1717 } 1718 if ( refVal->GetType() == SbxOBJECT && !bObjAssign && ( dynamic_cast<const SbxMethod *>(refVal.get()) != nullptr || ! refVal->GetParent() ) ) 1719 { 1720 SbxVariable* pDflt = getDefaultProp( refVal.get() ); 1721 if ( pDflt ) 1722 refVal = pDflt; 1723 } 1724 } 1725 1726 if ( !checkUnoStructCopy( bVBAEnabled, refVal, refVar ) ) 1727 *refVar = *refVal; 1728 1729 if( bFlagsChanged ) 1730 refVar->SetFlags( n ); 1731 } 1732 1733 namespace { 1734 1735 // VBA Dim As New behavior handling, save init object information 1736 struct DimAsNewRecoverItem 1737 { 1738 OUString m_aObjClass; 1739 OUString m_aObjName; 1740 SbxObject* m_pObjParent; 1741 SbModule* m_pClassModule; 1742 1743 DimAsNewRecoverItem() 1744 : m_pObjParent( nullptr ) 1745 , m_pClassModule( nullptr ) 1746 {} 1747 1748 DimAsNewRecoverItem( const OUString& rObjClass, const OUString& rObjName, 1749 SbxObject* pObjParent, SbModule* pClassModule ) 1750 : m_aObjClass( rObjClass ) 1751 , m_aObjName( rObjName ) 1752 , m_pObjParent( pObjParent ) 1753 , m_pClassModule( pClassModule ) 1754 {} 1755 1756 }; 1757 1758 1759 struct SbxVariablePtrHash 1760 { 1761 size_t operator()( SbxVariable* pVar ) const 1762 { return reinterpret_cast<size_t>(pVar); } 1763 }; 1764 1765 } 1766 1767 typedef std::unordered_map< SbxVariable*, DimAsNewRecoverItem, 1768 SbxVariablePtrHash > DimAsNewRecoverHash; 1769 1770 namespace { 1771 1772 DimAsNewRecoverHash gaDimAsNewRecoverHash; 1773 1774 } 1775 1776 void removeDimAsNewRecoverItem( SbxVariable* pVar ) 1777 { 1778 DimAsNewRecoverHash::iterator it = gaDimAsNewRecoverHash.find( pVar ); 1779 if( it != gaDimAsNewRecoverHash.end() ) 1780 { 1781 gaDimAsNewRecoverHash.erase( it ); 1782 } 1783 } 1784 1785 1786 // saving object variable 1787 // not-object variables will cause errors 1788 1789 constexpr OUStringLiteral pCollectionStr = u"Collection"; 1790 1791 void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp ) 1792 { 1793 // #67733 types with array-flag are OK too 1794 1795 // Check var, !object is no error for sure if, only if type is fixed 1796 SbxDataType eVarType = refVar->GetType(); 1797 if( !bHandleDefaultProp && eVarType != SbxOBJECT && !(eVarType & SbxARRAY) && refVar->IsFixed() ) 1798 { 1799 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1800 return; 1801 } 1802 1803 // Check value, !object is no error for sure if, only if type is fixed 1804 SbxDataType eValType = refVal->GetType(); 1805 if( !bHandleDefaultProp && eValType != SbxOBJECT && !(eValType & SbxARRAY) && refVal->IsFixed() ) 1806 { 1807 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1808 return; 1809 } 1810 1811 // Getting in here causes problems with objects with default properties 1812 // if they are SbxEMPTY I guess 1813 if ( !bHandleDefaultProp || eValType == SbxOBJECT ) 1814 { 1815 // activate GetObject for collections on refVal 1816 SbxBase* pObjVarObj = refVal->GetObject(); 1817 if( pObjVarObj ) 1818 { 1819 SbxVariableRef refObjVal = dynamic_cast<SbxObject*>( pObjVarObj ); 1820 1821 if( refObjVal.is() ) 1822 { 1823 refVal = refObjVal; 1824 } 1825 else if( !(eValType & SbxARRAY) ) 1826 { 1827 refVal = nullptr; 1828 } 1829 } 1830 } 1831 1832 // #52896 refVal can be invalid here, if uno-sequences - or more 1833 // general arrays - are assigned to variables that are declared 1834 // as an object! 1835 if( !refVal.is() ) 1836 { 1837 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1838 } 1839 else 1840 { 1841 bool bFlagsChanged = false; 1842 SbxFlagBits n = SbxFlagBits::NONE; 1843 if( refVar.get() == pMeth ) 1844 { 1845 bFlagsChanged = true; 1846 n = refVar->GetFlags(); 1847 refVar->SetFlag( SbxFlagBits::Write ); 1848 } 1849 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( refVar.get() ); 1850 if( pProcProperty ) 1851 { 1852 pProcProperty->setSet( true ); 1853 } 1854 if ( bHandleDefaultProp ) 1855 { 1856 // get default properties for lhs & rhs where necessary 1857 // SbxVariable* defaultProp = NULL; unused variable 1858 // LHS try determine if a default prop exists 1859 // again like in StepPUT (see there too ) we are tweaking the 1860 // heuristics again for when to assign an object reference or 1861 // use default members if they exist 1862 // #FIXME we really need to get to the bottom of this mess 1863 bool bObjAssign = false; 1864 if ( refVar->GetType() == SbxOBJECT ) 1865 { 1866 if ( dynamic_cast<const SbxMethod *>(refVar.get()) != nullptr || ! refVar->GetParent() ) 1867 { 1868 SbxVariable* pDflt = getDefaultProp( refVar.get() ); 1869 if ( pDflt ) 1870 { 1871 refVar = pDflt; 1872 } 1873 } 1874 else 1875 bObjAssign = true; 1876 } 1877 // RHS only get a default prop is the rhs has one 1878 if ( refVal->GetType() == SbxOBJECT ) 1879 { 1880 // check if lhs is a null object 1881 // if it is then use the object not the default property 1882 SbxObject* pObj = dynamic_cast<SbxObject*>( refVar.get() ); 1883 1884 // calling GetObject on a SbxEMPTY variable raises 1885 // object not set errors, make sure it's an Object 1886 if ( !pObj && refVar->GetType() == SbxOBJECT ) 1887 { 1888 SbxBase* pObjVarObj = refVar->GetObject(); 1889 pObj = dynamic_cast<SbxObject*>( pObjVarObj ); 1890 } 1891 SbxVariable* pDflt = nullptr; 1892 if ( pObj && !bObjAssign ) 1893 { 1894 // lhs is either a valid object || or has a defaultProp 1895 pDflt = getDefaultProp( refVal.get() ); 1896 } 1897 if ( pDflt ) 1898 { 1899 refVal = pDflt; 1900 } 1901 } 1902 } 1903 1904 // Handle Dim As New 1905 bool bDimAsNew = bVBAEnabled && refVar->IsSet( SbxFlagBits::DimAsNew ); 1906 SbxBaseRef xPrevVarObj; 1907 if( bDimAsNew ) 1908 { 1909 xPrevVarObj = refVar->GetObject(); 1910 } 1911 // Handle withevents 1912 bool bWithEvents = refVar->IsSet( SbxFlagBits::WithEvents ); 1913 if ( bWithEvents ) 1914 { 1915 Reference< XInterface > xComListener; 1916 1917 SbxBase* pObj = refVal->GetObject(); 1918 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj ); 1919 if( pUnoObj != nullptr ) 1920 { 1921 Any aControlAny = pUnoObj->getUnoAny(); 1922 OUString aDeclareClassName = refVar->GetDeclareClassName(); 1923 OUString aPrefix = refVar->GetName(); 1924 SbxObjectRef xScopeObj = refVar->GetParent(); 1925 xComListener = createComListener( aControlAny, aDeclareClassName, aPrefix, xScopeObj ); 1926 1927 refVal->SetDeclareClassName( aDeclareClassName ); 1928 refVal->SetComListener( xComListener, &rBasic ); // Hold reference 1929 } 1930 1931 } 1932 1933 // lhs is a property who's value is currently (Empty e.g. no broadcast yet) 1934 // in this case if there is a default prop involved the value of the 1935 // default property may in fact be void so the type will also be SbxEMPTY 1936 // in this case we do not want to call checkUnoStructCopy 'cause that will 1937 // cause an error also 1938 if ( !checkUnoStructCopy( bHandleDefaultProp, refVal, refVar ) ) 1939 { 1940 *refVar = *refVal; 1941 } 1942 if ( bDimAsNew ) 1943 { 1944 if( dynamic_cast<const SbxObject*>( refVar.get() ) == nullptr ) 1945 { 1946 SbxBase* pValObjBase = refVal->GetObject(); 1947 if( pValObjBase == nullptr ) 1948 { 1949 if( xPrevVarObj.is() ) 1950 { 1951 // Object is overwritten with NULL, instantiate init object 1952 DimAsNewRecoverHash::iterator it = gaDimAsNewRecoverHash.find( refVar.get() ); 1953 if( it != gaDimAsNewRecoverHash.end() ) 1954 { 1955 const DimAsNewRecoverItem& rItem = it->second; 1956 if( rItem.m_pClassModule != nullptr ) 1957 { 1958 SbClassModuleObject* pNewObj = new SbClassModuleObject( rItem.m_pClassModule ); 1959 pNewObj->SetName( rItem.m_aObjName ); 1960 pNewObj->SetParent( rItem.m_pObjParent ); 1961 refVar->PutObject( pNewObj ); 1962 } 1963 else if( rItem.m_aObjClass.equalsIgnoreAsciiCase( pCollectionStr ) ) 1964 { 1965 BasicCollection* pNewCollection = new BasicCollection( pCollectionStr ); 1966 pNewCollection->SetName( rItem.m_aObjName ); 1967 pNewCollection->SetParent( rItem.m_pObjParent ); 1968 refVar->PutObject( pNewCollection ); 1969 } 1970 } 1971 } 1972 } 1973 else 1974 { 1975 // Does old value exist? 1976 bool bFirstInit = !xPrevVarObj.is(); 1977 if( bFirstInit ) 1978 { 1979 // Store information to instantiate object later 1980 SbxObject* pValObj = dynamic_cast<SbxObject*>( pValObjBase ); 1981 if( pValObj != nullptr ) 1982 { 1983 OUString aObjClass = pValObj->GetClassName(); 1984 1985 SbClassModuleObject* pClassModuleObj = dynamic_cast<SbClassModuleObject*>( pValObjBase ); 1986 if( pClassModuleObj != nullptr ) 1987 { 1988 SbModule* pClassModule = pClassModuleObj->getClassModule(); 1989 gaDimAsNewRecoverHash[refVar.get()] = 1990 DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), pClassModule ); 1991 } 1992 else if( aObjClass.equalsIgnoreAsciiCase( "Collection" ) ) 1993 { 1994 gaDimAsNewRecoverHash[refVar.get()] = 1995 DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), nullptr ); 1996 } 1997 } 1998 } 1999 } 2000 } 2001 } 2002 2003 if( bFlagsChanged ) 2004 { 2005 refVar->SetFlags( n ); 2006 } 2007 } 2008 } 2009 2010 void SbiRuntime::StepSET() 2011 { 2012 SbxVariableRef refVal = PopVar(); 2013 SbxVariableRef refVar = PopVar(); 2014 StepSET_Impl( refVal, refVar, bVBAEnabled ); // this is really assignment 2015 } 2016 2017 void SbiRuntime::StepVBASET() 2018 { 2019 SbxVariableRef refVal = PopVar(); 2020 SbxVariableRef refVar = PopVar(); 2021 // don't handle default property 2022 StepSET_Impl( refVal, refVar ); // set obj = something 2023 } 2024 2025 2026 void SbiRuntime::StepLSET() 2027 { 2028 SbxVariableRef refVal = PopVar(); 2029 SbxVariableRef refVar = PopVar(); 2030 if( refVar->GetType() != SbxSTRING || 2031 refVal->GetType() != SbxSTRING ) 2032 { 2033 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 2034 } 2035 else 2036 { 2037 SbxFlagBits n = refVar->GetFlags(); 2038 if( refVar.get() == pMeth ) 2039 { 2040 refVar->SetFlag( SbxFlagBits::Write ); 2041 } 2042 OUString aRefVarString = refVar->GetOUString(); 2043 OUString aRefValString = refVal->GetOUString(); 2044 2045 sal_Int32 nVarStrLen = aRefVarString.getLength(); 2046 sal_Int32 nValStrLen = aRefValString.getLength(); 2047 OUString aNewStr; 2048 if( nVarStrLen > nValStrLen ) 2049 { 2050 OUStringBuffer buf(aRefValString); 2051 comphelper::string::padToLength(buf, nVarStrLen, ' '); 2052 aNewStr = buf.makeStringAndClear(); 2053 } 2054 else 2055 { 2056 aNewStr = aRefValString.copy( 0, nVarStrLen ); 2057 } 2058 2059 refVar->PutString(aNewStr); 2060 refVar->SetFlags( n ); 2061 } 2062 } 2063 2064 void SbiRuntime::StepRSET() 2065 { 2066 SbxVariableRef refVal = PopVar(); 2067 SbxVariableRef refVar = PopVar(); 2068 if( refVar->GetType() != SbxSTRING || refVal->GetType() != SbxSTRING ) 2069 { 2070 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 2071 } 2072 else 2073 { 2074 SbxFlagBits n = refVar->GetFlags(); 2075 if( refVar.get() == pMeth ) 2076 { 2077 refVar->SetFlag( SbxFlagBits::Write ); 2078 } 2079 OUString aRefVarString = refVar->GetOUString(); 2080 OUString aRefValString = refVal->GetOUString(); 2081 sal_Int32 nVarStrLen = aRefVarString.getLength(); 2082 sal_Int32 nValStrLen = aRefValString.getLength(); 2083 2084 OUStringBuffer aNewStr(nVarStrLen); 2085 if (nVarStrLen > nValStrLen) 2086 { 2087 comphelper::string::padToLength(aNewStr, nVarStrLen - nValStrLen, ' '); 2088 aNewStr.append(aRefValString); 2089 } 2090 else 2091 { 2092 aNewStr.append(aRefValString.subView(0, nVarStrLen)); 2093 } 2094 refVar->PutString(aNewStr.makeStringAndClear()); 2095 2096 refVar->SetFlags( n ); 2097 } 2098 } 2099 2100 // laying down TOS in TOS-1, then set ReadOnly-Bit 2101 2102 void SbiRuntime::StepPUTC() 2103 { 2104 SbxVariableRef refVal = PopVar(); 2105 SbxVariableRef refVar = PopVar(); 2106 refVar->SetFlag( SbxFlagBits::Write ); 2107 *refVar = *refVal; 2108 refVar->ResetFlag( SbxFlagBits::Write ); 2109 refVar->SetFlag( SbxFlagBits::Const ); 2110 } 2111 2112 // DIM 2113 // TOS = variable for the array with dimension information as parameter 2114 2115 void SbiRuntime::StepDIM() 2116 { 2117 SbxVariableRef refVar = PopVar(); 2118 DimImpl( refVar ); 2119 } 2120 2121 // #56204 swap out DIM-functionality into a help method (step0.cxx) 2122 void SbiRuntime::DimImpl(const SbxVariableRef& refVar) 2123 { 2124 // If refDim then this DIM statement is terminating a ReDIM and 2125 // previous StepERASE_CLEAR for an array, the following actions have 2126 // been delayed from ( StepERASE_CLEAR ) 'till here 2127 if ( refRedim.is() ) 2128 { 2129 if ( !refRedimpArray.is() ) // only erase the array not ReDim Preserve 2130 { 2131 lcl_eraseImpl( refVar, bVBAEnabled ); 2132 } 2133 SbxDataType eType = refVar->GetType(); 2134 lcl_clearImpl( refVar, eType ); 2135 refRedim = nullptr; 2136 } 2137 SbxArray* pDims = refVar->GetParameters(); 2138 // must have an even number of arguments 2139 // have in mind that Arg[0] does not count! 2140 if (pDims && !(pDims->Count() & 1)) 2141 { 2142 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2143 } 2144 else 2145 { 2146 SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT; 2147 SbxDimArray* pArray = new SbxDimArray( eType ); 2148 // allow arrays without dimension information, too (VB-compatible) 2149 if( pDims ) 2150 { 2151 refVar->ResetFlag( SbxFlagBits::VarToDim ); 2152 2153 for (sal_uInt32 i = 1; i < pDims->Count();) 2154 { 2155 sal_Int32 lb = pDims->Get(i++)->GetLong(); 2156 sal_Int32 ub = pDims->Get(i++)->GetLong(); 2157 if( ub < lb ) 2158 { 2159 Error( ERRCODE_BASIC_OUT_OF_RANGE ); 2160 ub = lb; 2161 } 2162 pArray->AddDim(lb, ub); 2163 if ( lb != ub ) 2164 { 2165 pArray->setHasFixedSize( true ); 2166 } 2167 } 2168 } 2169 else 2170 { 2171 // #62867 On creating an array of the length 0, create 2172 // a dimension (like for Uno-Sequences of the length 0) 2173 pArray->unoAddDim(0, -1); 2174 } 2175 SbxFlagBits nSavFlags = refVar->GetFlags(); 2176 refVar->ResetFlag( SbxFlagBits::Fixed ); 2177 refVar->PutObject( pArray ); 2178 refVar->SetFlags( nSavFlags ); 2179 refVar->SetParameters( nullptr ); 2180 } 2181 } 2182 2183 // REDIM 2184 // TOS = variable for the array 2185 // argv = dimension information 2186 2187 void SbiRuntime::StepREDIM() 2188 { 2189 // Nothing different than dim at the moment because 2190 // a double dim is already recognized by the compiler. 2191 StepDIM(); 2192 } 2193 2194 2195 // Helper function for StepREDIMP and StepDCREATE_IMPL / bRedimp = true 2196 static void implCopyDimArray( SbxDimArray* pNewArray, SbxDimArray* pOldArray, sal_Int32 nMaxDimIndex, 2197 sal_Int32 nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds ) 2198 { 2199 sal_Int32& ri = pActualIndices[nActualDim]; 2200 for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ ) 2201 { 2202 if( nActualDim < nMaxDimIndex ) 2203 { 2204 implCopyDimArray( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1, 2205 pActualIndices, pLowerBounds, pUpperBounds ); 2206 } 2207 else 2208 { 2209 SbxVariable* pSource = pOldArray->Get(pActualIndices); 2210 if (pSource && pOldArray->GetRefCount() > 1) 2211 // tdf#134692: old array will stay alive after the redim - we need to copy deep 2212 pSource = new SbxVariable(*pSource); 2213 pNewArray->Put(pSource, pActualIndices); 2214 } 2215 } 2216 } 2217 2218 // Returns true when actually restored 2219 static bool implRestorePreservedArray(SbxDimArray* pNewArray, SbxArrayRef& rrefRedimpArray, bool* pbWasError = nullptr) 2220 { 2221 assert(pNewArray); 2222 bool bResult = false; 2223 if (pbWasError) 2224 *pbWasError = false; 2225 if (rrefRedimpArray) 2226 { 2227 SbxDimArray* pOldArray = static_cast<SbxDimArray*>(rrefRedimpArray.get()); 2228 const sal_Int32 nDimsNew = pNewArray->GetDims(); 2229 const sal_Int32 nDimsOld = pOldArray->GetDims(); 2230 2231 if (nDimsOld != nDimsNew) 2232 { 2233 StarBASIC::Error(ERRCODE_BASIC_OUT_OF_RANGE); 2234 if (pbWasError) 2235 *pbWasError = true; 2236 } 2237 else if (nDimsNew > 0) 2238 { 2239 // Store dims to use them for copying later 2240 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDimsNew]); 2241 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDimsNew]); 2242 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDimsNew]); 2243 bool bNeedsPreallocation = true; 2244 2245 // Compare bounds 2246 for (sal_Int32 i = 1; i <= nDimsNew; i++) 2247 { 2248 sal_Int32 lBoundNew, uBoundNew; 2249 sal_Int32 lBoundOld, uBoundOld; 2250 pNewArray->GetDim(i, lBoundNew, uBoundNew); 2251 pOldArray->GetDim(i, lBoundOld, uBoundOld); 2252 lBoundNew = std::max(lBoundNew, lBoundOld); 2253 uBoundNew = std::min(uBoundNew, uBoundOld); 2254 sal_Int32 j = i - 1; 2255 pActualIndices[j] = pLowerBounds[j] = lBoundNew; 2256 pUpperBounds[j] = uBoundNew; 2257 if (lBoundNew > uBoundNew) // No elements in the dimension -> no elements to restore 2258 bNeedsPreallocation = false; 2259 } 2260 2261 // Optimization: pre-allocate underlying container 2262 if (bNeedsPreallocation) 2263 pNewArray->Put(nullptr, pUpperBounds.get()); 2264 2265 // Copy data from old array by going recursively through all dimensions 2266 // (It would be faster to work on the flat internal data array of an 2267 // SbyArray but this solution is clearer and easier) 2268 implCopyDimArray(pNewArray, pOldArray, nDimsNew - 1, 0, pActualIndices.get(), 2269 pLowerBounds.get(), pUpperBounds.get()); 2270 bResult = true; 2271 } 2272 2273 rrefRedimpArray.clear(); 2274 } 2275 return bResult; 2276 } 2277 2278 // REDIM PRESERVE 2279 // TOS = variable for the array 2280 // argv = dimension information 2281 2282 void SbiRuntime::StepREDIMP() 2283 { 2284 SbxVariableRef refVar = PopVar(); 2285 DimImpl( refVar ); 2286 2287 // Now check, if we can copy from the old array 2288 if( refRedimpArray.is() ) 2289 { 2290 if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(refVar->GetObject())) 2291 implRestorePreservedArray(pNewArray, refRedimpArray); 2292 } 2293 } 2294 2295 // REDIM_COPY 2296 // TOS = Array-Variable, Reference to array is copied 2297 // Variable is cleared as in ERASE 2298 2299 void SbiRuntime::StepREDIMP_ERASE() 2300 { 2301 SbxVariableRef refVar = PopVar(); 2302 refRedim = refVar; 2303 SbxDataType eType = refVar->GetType(); 2304 if( eType & SbxARRAY ) 2305 { 2306 SbxBase* pElemObj = refVar->GetObject(); 2307 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 2308 if( pDimArray ) 2309 { 2310 refRedimpArray = pDimArray; 2311 } 2312 2313 } 2314 else if( refVar->IsFixed() ) 2315 { 2316 refVar->Clear(); 2317 } 2318 else 2319 { 2320 refVar->SetType( SbxEMPTY ); 2321 } 2322 } 2323 2324 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType ) 2325 { 2326 SbxFlagBits nSavFlags = refVar->GetFlags(); 2327 refVar->ResetFlag( SbxFlagBits::Fixed ); 2328 refVar->SetType( SbxDataType(eType & 0x0FFF) ); 2329 refVar->SetFlags( nSavFlags ); 2330 refVar->Clear(); 2331 } 2332 2333 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled ) 2334 { 2335 SbxDataType eType = refVar->GetType(); 2336 if( eType & SbxARRAY ) 2337 { 2338 if ( bVBAEnabled ) 2339 { 2340 SbxBase* pElemObj = refVar->GetObject(); 2341 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 2342 if( pDimArray ) 2343 { 2344 if ( pDimArray->hasFixedSize() ) 2345 { 2346 // Clear all Value(s) 2347 pDimArray->SbxArray::Clear(); 2348 } 2349 else 2350 { 2351 pDimArray->Clear(); // clear dims and values 2352 } 2353 } 2354 else 2355 { 2356 SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj ); 2357 if ( pArray ) 2358 { 2359 pArray->Clear(); 2360 } 2361 } 2362 } 2363 else 2364 { 2365 // Arrays have on an erase to VB quite a complex behaviour. Here are 2366 // only the type problems at REDIM (#26295) removed at first: 2367 // Set type hard onto the array-type, because a variable with array is 2368 // SbxOBJECT. At REDIM there's an SbxOBJECT-array generated then and 2369 // the original type is lost -> runtime error 2370 lcl_clearImpl( refVar, eType ); 2371 } 2372 } 2373 else if( refVar->IsFixed() ) 2374 { 2375 refVar->Clear(); 2376 } 2377 else 2378 { 2379 refVar->SetType( SbxEMPTY ); 2380 } 2381 } 2382 2383 // delete variable 2384 // TOS = variable 2385 2386 void SbiRuntime::StepERASE() 2387 { 2388 SbxVariableRef refVar = PopVar(); 2389 lcl_eraseImpl( refVar, bVBAEnabled ); 2390 } 2391 2392 void SbiRuntime::StepERASE_CLEAR() 2393 { 2394 refRedim = PopVar(); 2395 } 2396 2397 void SbiRuntime::StepARRAYACCESS() 2398 { 2399 if( !refArgv.is() ) 2400 { 2401 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2402 } 2403 SbxVariableRef refVar = PopVar(); 2404 refVar->SetParameters( refArgv.get() ); 2405 PopArgv(); 2406 PushVar( CheckArray( refVar.get() ) ); 2407 } 2408 2409 void SbiRuntime::StepBYVAL() 2410 { 2411 // Copy variable on stack to break call by reference 2412 SbxVariableRef pVar = PopVar(); 2413 SbxDataType t = pVar->GetType(); 2414 2415 SbxVariable* pCopyVar = new SbxVariable( t ); 2416 pCopyVar->SetFlag( SbxFlagBits::ReadWrite ); 2417 *pCopyVar = *pVar; 2418 2419 PushVar( pCopyVar ); 2420 } 2421 2422 // establishing an argv 2423 // nOp1 stays as it is -> 1st element is the return value 2424 2425 void SbiRuntime::StepARGC() 2426 { 2427 PushArgv(); 2428 refArgv = new SbxArray; 2429 nArgc = 1; 2430 } 2431 2432 // storing an argument in Argv 2433 2434 void SbiRuntime::StepARGV() 2435 { 2436 if( !refArgv.is() ) 2437 { 2438 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2439 } 2440 else 2441 { 2442 SbxVariableRef pVal = PopVar(); 2443 2444 // Before fix of #94916: 2445 if( dynamic_cast<const SbxMethod*>( pVal.get() ) != nullptr 2446 || dynamic_cast<const SbUnoProperty*>( pVal.get() ) != nullptr 2447 || dynamic_cast<const SbProcedureProperty*>( pVal.get() ) != nullptr ) 2448 { 2449 // evaluate methods and properties! 2450 SbxVariable* pRes = new SbxVariable( *pVal ); 2451 pVal = pRes; 2452 } 2453 refArgv->Put(pVal.get(), nArgc++); 2454 } 2455 } 2456 2457 // Input to Variable. The variable is on TOS and is 2458 // is removed afterwards. 2459 void SbiRuntime::StepINPUT() 2460 { 2461 OUStringBuffer sin; 2462 char ch = 0; 2463 ErrCode err; 2464 // Skip whitespace 2465 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2466 { 2467 ch = pIosys->Read(); 2468 if( ch != ' ' && ch != '\t' && ch != '\n' ) 2469 { 2470 break; 2471 } 2472 } 2473 if( !err ) 2474 { 2475 // Scan until comma or whitespace 2476 char sep = ( ch == '"' ) ? ch : 0; 2477 if( sep ) 2478 { 2479 ch = pIosys->Read(); 2480 } 2481 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2482 { 2483 if( ch == sep ) 2484 { 2485 ch = pIosys->Read(); 2486 if( ch != sep ) 2487 { 2488 break; 2489 } 2490 } 2491 else if( !sep && (ch == ',' || ch == '\n') ) 2492 { 2493 break; 2494 } 2495 sin.append( ch ); 2496 ch = pIosys->Read(); 2497 } 2498 // skip whitespace 2499 if( ch == ' ' || ch == '\t' ) 2500 { 2501 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2502 { 2503 if( ch != ' ' && ch != '\t' && ch != '\n' ) 2504 { 2505 break; 2506 } 2507 ch = pIosys->Read(); 2508 } 2509 } 2510 } 2511 if( !err ) 2512 { 2513 OUString s = sin.makeStringAndClear(); 2514 SbxVariableRef pVar = GetTOS(); 2515 // try to fill the variable with a numeric value first, 2516 // then with a string value 2517 if( !pVar->IsFixed() || pVar->IsNumeric() ) 2518 { 2519 sal_uInt16 nLen = 0; 2520 if( !pVar->Scan( s, &nLen ) ) 2521 { 2522 err = SbxBase::GetError(); 2523 SbxBase::ResetError(); 2524 } 2525 // the value has to be scanned in completely 2526 else if( nLen != s.getLength() && !pVar->PutString( s ) ) 2527 { 2528 err = SbxBase::GetError(); 2529 SbxBase::ResetError(); 2530 } 2531 else if( nLen != s.getLength() && pVar->IsNumeric() ) 2532 { 2533 err = SbxBase::GetError(); 2534 SbxBase::ResetError(); 2535 if( !err ) 2536 { 2537 err = ERRCODE_BASIC_CONVERSION; 2538 } 2539 } 2540 } 2541 else 2542 { 2543 pVar->PutString( s ); 2544 err = SbxBase::GetError(); 2545 SbxBase::ResetError(); 2546 } 2547 } 2548 if( err == ERRCODE_BASIC_USER_ABORT ) 2549 { 2550 Error( err ); 2551 } 2552 else if( err ) 2553 { 2554 if( pRestart && !pIosys->GetChannel() ) 2555 { 2556 pCode = pRestart; 2557 } 2558 else 2559 { 2560 Error( err ); 2561 } 2562 } 2563 else 2564 { 2565 PopVar(); 2566 } 2567 } 2568 2569 // Line Input to Variable. The variable is on TOS and is 2570 // deleted afterwards. 2571 2572 void SbiRuntime::StepLINPUT() 2573 { 2574 OString aInput; 2575 pIosys->Read( aInput ); 2576 Error( pIosys->GetError() ); 2577 SbxVariableRef p = PopVar(); 2578 p->PutString(OStringToOUString(aInput, osl_getThreadTextEncoding())); 2579 } 2580 2581 // end of program 2582 2583 void SbiRuntime::StepSTOP() 2584 { 2585 pInst->Stop(); 2586 } 2587 2588 2589 void SbiRuntime::StepINITFOR() 2590 { 2591 PushFor(); 2592 } 2593 2594 void SbiRuntime::StepINITFOREACH() 2595 { 2596 PushForEach(); 2597 } 2598 2599 // increment FOR-variable 2600 2601 void SbiRuntime::StepNEXT() 2602 { 2603 if( !pForStk ) 2604 { 2605 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2606 return; 2607 } 2608 if (pForStk->eForType != ForType::To) 2609 return; 2610 if (!pForStk->refVar) 2611 { 2612 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2613 return; 2614 } 2615 // tdf#85371 - grant explicitly write access to the index variable 2616 // since it could be the name of a method itself used in the next statement. 2617 ScopedWritableGuard aGuard(pForStk->refVar, pForStk->refVar.get() == pMeth); 2618 pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc ); 2619 } 2620 2621 // beginning CASE: TOS in CASE-stack 2622 2623 void SbiRuntime::StepCASE() 2624 { 2625 if( !refCaseStk.is() ) 2626 { 2627 refCaseStk = new SbxArray; 2628 } 2629 SbxVariableRef xVar = PopVar(); 2630 refCaseStk->Put(xVar.get(), refCaseStk->Count()); 2631 } 2632 2633 // end CASE: free variable 2634 2635 void SbiRuntime::StepENDCASE() 2636 { 2637 if (!refCaseStk.is() || !refCaseStk->Count()) 2638 { 2639 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2640 } 2641 else 2642 { 2643 refCaseStk->Remove(refCaseStk->Count() - 1); 2644 } 2645 } 2646 2647 2648 void SbiRuntime::StepSTDERROR() 2649 { 2650 pError = nullptr; bError = true; 2651 pInst->aErrorMsg.clear(); 2652 pInst->nErr = ERRCODE_NONE; 2653 pInst->nErl = 0; 2654 nError = ERRCODE_NONE; 2655 SbxErrObject::getUnoErrObject()->Clear(); 2656 } 2657 2658 void SbiRuntime::StepNOERROR() 2659 { 2660 pInst->aErrorMsg.clear(); 2661 pInst->nErr = ERRCODE_NONE; 2662 pInst->nErl = 0; 2663 nError = ERRCODE_NONE; 2664 SbxErrObject::getUnoErrObject()->Clear(); 2665 bError = false; 2666 } 2667 2668 // leave UP 2669 2670 void SbiRuntime::StepLEAVE() 2671 { 2672 bRun = false; 2673 // If VBA and we are leaving an ErrorHandler then clear the error ( it's been processed ) 2674 if ( bInError && pError ) 2675 { 2676 SbxErrObject::getUnoErrObject()->Clear(); 2677 } 2678 } 2679 2680 void SbiRuntime::StepCHANNEL() // TOS = channel number 2681 { 2682 SbxVariableRef pChan = PopVar(); 2683 short nChan = pChan->GetInteger(); 2684 pIosys->SetChannel( nChan ); 2685 Error( pIosys->GetError() ); 2686 } 2687 2688 void SbiRuntime::StepCHANNEL0() 2689 { 2690 pIosys->ResetChannel(); 2691 } 2692 2693 void SbiRuntime::StepPRINT() // print TOS 2694 { 2695 SbxVariableRef p = PopVar(); 2696 OUString s1 = p->GetOUString(); 2697 OUString s; 2698 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) 2699 { 2700 s = " "; // one blank before 2701 } 2702 s += s1; 2703 pIosys->Write( s ); 2704 Error( pIosys->GetError() ); 2705 } 2706 2707 void SbiRuntime::StepPRINTF() // print TOS in field 2708 { 2709 SbxVariableRef p = PopVar(); 2710 OUString s1 = p->GetOUString(); 2711 OUStringBuffer s; 2712 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) 2713 { 2714 s.append(' '); 2715 } 2716 s.append(s1); 2717 comphelper::string::padToLength(s, 14, ' '); 2718 pIosys->Write( s.makeStringAndClear() ); 2719 Error( pIosys->GetError() ); 2720 } 2721 2722 void SbiRuntime::StepWRITE() // write TOS 2723 { 2724 SbxVariableRef p = PopVar(); 2725 // Does the string have to be encapsulated? 2726 char ch = 0; 2727 switch (p->GetType() ) 2728 { 2729 case SbxSTRING: ch = '"'; break; 2730 case SbxCURRENCY: 2731 case SbxBOOL: 2732 case SbxDATE: ch = '#'; break; 2733 default: break; 2734 } 2735 OUString s; 2736 if( ch ) 2737 { 2738 s += OUStringChar(ch); 2739 } 2740 s += p->GetOUString(); 2741 if( ch ) 2742 { 2743 s += OUStringChar(ch); 2744 } 2745 pIosys->Write( s ); 2746 Error( pIosys->GetError() ); 2747 } 2748 2749 void SbiRuntime::StepRENAME() // Rename Tos+1 to Tos 2750 { 2751 SbxVariableRef pTos1 = PopVar(); 2752 SbxVariableRef pTos = PopVar(); 2753 OUString aDest = pTos1->GetOUString(); 2754 OUString aSource = pTos->GetOUString(); 2755 2756 if( hasUno() ) 2757 { 2758 implStepRenameUCB( aSource, aDest ); 2759 } 2760 else 2761 { 2762 implStepRenameOSL( aSource, aDest ); 2763 } 2764 } 2765 2766 // TOS = Prompt 2767 2768 void SbiRuntime::StepPROMPT() 2769 { 2770 SbxVariableRef p = PopVar(); 2771 OString aStr(OUStringToOString(p->GetOUString(), osl_getThreadTextEncoding())); 2772 pIosys->SetPrompt( aStr ); 2773 } 2774 2775 // Set Restart point 2776 2777 void SbiRuntime::StepRESTART() 2778 { 2779 pRestart = pCode; 2780 } 2781 2782 // empty expression on stack for missing parameter 2783 2784 void SbiRuntime::StepEMPTY() 2785 { 2786 // #57915 The semantics of StepEMPTY() is the representation of a missing argument. 2787 // This is represented by the value 448 (ERRCODE_BASIC_NAMED_NOT_FOUND) of the type error 2788 // in VB. StepEmpty should now rather be named StepMISSING() but the name is kept 2789 // to simplify matters. 2790 SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); 2791 xVar->PutErr( 448 ); 2792 // tdf#79426, tdf#125180 - add additional information about a missing parameter 2793 SetIsMissing( xVar.get() ); 2794 PushVar( xVar.get() ); 2795 } 2796 2797 // TOS = error code 2798 2799 void SbiRuntime::StepERROR() 2800 { 2801 SbxVariableRef refCode = PopVar(); 2802 sal_uInt16 n = refCode->GetUShort(); 2803 ErrCode error = StarBASIC::GetSfxFromVBError( n ); 2804 if ( bVBAEnabled ) 2805 { 2806 pInst->Error( error ); 2807 } 2808 else 2809 { 2810 Error( error ); 2811 } 2812 } 2813 2814 // loading a numeric constant (+ID) 2815 2816 void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 ) 2817 { 2818 // tdf#143707 - check if the data type character was added after the string termination symbol 2819 SbxDataType eTypeStr; 2820 // #57844 use localized function 2821 OUString aStr = pImg->GetString(static_cast<short>(nOp1), &eTypeStr); 2822 // also allow , !!! 2823 sal_Int32 iComma = aStr.indexOf(','); 2824 if( iComma >= 0 ) 2825 { 2826 aStr = aStr.replaceAt(iComma, 1, "."); 2827 } 2828 sal_Int32 nParseEnd = 0; 2829 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; 2830 double n = ::rtl::math::stringToDouble( aStr, '.', ',', &eStatus, &nParseEnd ); 2831 2832 // tdf#131296 - retrieve data type put in SbiExprNode::Gen 2833 SbxDataType eType = SbxDOUBLE; 2834 if ( nParseEnd < aStr.getLength() ) 2835 { 2836 // tdf#143707 - Check if there was a data type character after the numeric constant, 2837 // added by older versions of the fix of the default values for strings. 2838 switch ( aStr[nParseEnd] ) 2839 { 2840 // See GetSuffixType in basic/source/comp/scanner.cxx for type characters 2841 case '%': eType = SbxINTEGER; break; 2842 case '&': eType = SbxLONG; break; 2843 case '!': eType = SbxSINGLE; break; 2844 case '@': eType = SbxCURRENCY; break; 2845 // tdf#142460 - properly handle boolean values in string pool 2846 case 'b': eType = SbxBOOL; break; 2847 } 2848 } 2849 // tdf#143707 - if the data type character is different from the default value, it was added 2850 // in basic/source/comp/symtbl.cxx. Hence, change the type of the numeric constant to be loaded. 2851 else if (eTypeStr != SbxSTRING) 2852 { 2853 eType = eTypeStr; 2854 } 2855 SbxVariable* p = new SbxVariable( eType ); 2856 p->PutDouble( n ); 2857 // tdf#133913 - create variable with Variant/Type in order to prevent type conversion errors 2858 p->ResetFlag( SbxFlagBits::Fixed ); 2859 PushVar( p ); 2860 } 2861 2862 // loading a string constant (+ID) 2863 2864 void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 ) 2865 { 2866 SbxVariable* p = new SbxVariable; 2867 p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) ); 2868 PushVar( p ); 2869 } 2870 2871 // Immediate Load (+value) 2872 // The opcode is not generated in SbiExprNode::Gen anymore; used for legacy images 2873 2874 void SbiRuntime::StepLOADI( sal_uInt32 nOp1 ) 2875 { 2876 SbxVariable* p = new SbxVariable; 2877 p->PutInteger( static_cast<sal_Int16>( nOp1 ) ); 2878 PushVar( p ); 2879 } 2880 2881 // store a named argument in Argv (+Arg-no. from 1!) 2882 2883 void SbiRuntime::StepARGN( sal_uInt32 nOp1 ) 2884 { 2885 if( !refArgv.is() ) 2886 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2887 else 2888 { 2889 OUString aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) ); 2890 SbxVariableRef pVal = PopVar(); 2891 if( bVBAEnabled && 2892 ( dynamic_cast<const SbxMethod*>( pVal.get()) != nullptr 2893 || dynamic_cast<const SbUnoProperty*>( pVal.get()) != nullptr 2894 || dynamic_cast<const SbProcedureProperty*>( pVal.get()) != nullptr ) ) 2895 { 2896 // named variables ( that are Any especially properties ) can be empty at this point and need a broadcast 2897 if ( pVal->GetType() == SbxEMPTY ) 2898 pVal->Broadcast( SfxHintId::BasicDataWanted ); 2899 // evaluate methods and properties! 2900 SbxVariable* pRes = new SbxVariable( *pVal ); 2901 pVal = pRes; 2902 } 2903 refArgv->Put(pVal.get(), nArgc); 2904 refArgv->PutAlias(aAlias, nArgc++); 2905 } 2906 } 2907 2908 // converting the type of an argument in Argv for DECLARE-Fkt. (+type) 2909 2910 void SbiRuntime::StepARGTYP( sal_uInt32 nOp1 ) 2911 { 2912 if( !refArgv.is() ) 2913 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2914 else 2915 { 2916 bool bByVal = (nOp1 & 0x8000) != 0; // Is BYVAL requested? 2917 SbxDataType t = static_cast<SbxDataType>(nOp1 & 0x7FFF); 2918 SbxVariable* pVar = refArgv->Get(refArgv->Count() - 1); // last Arg 2919 2920 // check BYVAL 2921 if( pVar->GetRefCount() > 2 ) // 2 is normal for BYVAL 2922 { 2923 // parameter is a reference 2924 if( bByVal ) 2925 { 2926 // Call by Value is requested -> create a copy 2927 pVar = new SbxVariable( *pVar ); 2928 pVar->SetFlag( SbxFlagBits::ReadWrite ); 2929 refExprStk->Put(pVar, refArgv->Count() - 1); 2930 } 2931 else 2932 pVar->SetFlag( SbxFlagBits::Reference ); // Ref-Flag for DllMgr 2933 } 2934 else 2935 { 2936 // parameter is NO reference 2937 if( bByVal ) 2938 pVar->ResetFlag( SbxFlagBits::Reference ); // no reference -> OK 2939 else 2940 Error( ERRCODE_BASIC_BAD_PARAMETERS ); // reference needed 2941 } 2942 2943 if( pVar->GetType() != t ) 2944 { 2945 // variant for correct conversion 2946 // besides error, if SbxBYREF 2947 pVar->Convert( SbxVARIANT ); 2948 pVar->Convert( t ); 2949 } 2950 } 2951 } 2952 2953 // bring string to a definite length (+length) 2954 2955 void SbiRuntime::StepPAD( sal_uInt32 nOp1 ) 2956 { 2957 SbxVariable* p = GetTOS(); 2958 OUString s = p->GetOUString(); 2959 sal_Int32 nLen(nOp1); 2960 if( s.getLength() == nLen ) 2961 return; 2962 2963 OUStringBuffer aBuf(s); 2964 if (aBuf.getLength() > nLen) 2965 { 2966 comphelper::string::truncateToLength(aBuf, nLen); 2967 } 2968 else 2969 { 2970 comphelper::string::padToLength(aBuf, nLen, ' '); 2971 } 2972 s = aBuf.makeStringAndClear(); 2973 } 2974 2975 // jump (+target) 2976 2977 void SbiRuntime::StepJUMP( sal_uInt32 nOp1 ) 2978 { 2979 #ifdef DBG_UTIL 2980 // #QUESTION shouldn't this be 2981 // if( (sal_uInt8*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() ) 2982 if( nOp1 >= pImg->GetCodeSize() ) 2983 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2984 #endif 2985 pCode = pImg->GetCode() + nOp1; 2986 } 2987 2988 bool SbiRuntime::EvaluateTopOfStackAsBool() 2989 { 2990 SbxVariableRef tos = PopVar(); 2991 // In a test e.g. If Null then 2992 // will evaluate Null will act as if False 2993 if ( bVBAEnabled && tos->IsNull() ) 2994 { 2995 return false; 2996 } 2997 if ( tos->IsObject() ) 2998 { 2999 //GetBool applied to an Object attempts to dereference and evaluate 3000 //the underlying value as Bool. Here, we're checking rather that 3001 //it is not null 3002 return tos->GetObject(); 3003 } 3004 else 3005 { 3006 return tos->GetBool(); 3007 } 3008 } 3009 3010 // evaluate TOS, conditional jump (+target) 3011 3012 void SbiRuntime::StepJUMPT( sal_uInt32 nOp1 ) 3013 { 3014 if ( EvaluateTopOfStackAsBool() ) 3015 { 3016 StepJUMP( nOp1 ); 3017 } 3018 } 3019 3020 // evaluate TOS, conditional jump (+target) 3021 3022 void SbiRuntime::StepJUMPF( sal_uInt32 nOp1 ) 3023 { 3024 if ( !EvaluateTopOfStackAsBool() ) 3025 { 3026 StepJUMP( nOp1 ); 3027 } 3028 } 3029 3030 // evaluate TOS, jump into JUMP-table (+MaxVal) 3031 // looks like this: 3032 // ONJUMP 2 3033 // JUMP target1 3034 // JUMP target2 3035 3036 // if 0x8000 is set in the operand, push the return address (ON..GOSUB) 3037 3038 void SbiRuntime::StepONJUMP( sal_uInt32 nOp1 ) 3039 { 3040 SbxVariableRef p = PopVar(); 3041 sal_Int16 n = p->GetInteger(); 3042 if( nOp1 & 0x8000 ) 3043 { 3044 nOp1 &= 0x7FFF; 3045 PushGosub( pCode + 5 * nOp1 ); 3046 } 3047 if( n < 1 || o3tl::make_unsigned(n) > nOp1 ) 3048 n = static_cast<sal_Int16>( nOp1 + 1 ); 3049 nOp1 = static_cast<sal_uInt32>(pCode - pImg->GetCode()) + 5 * --n; 3050 StepJUMP( nOp1 ); 3051 } 3052 3053 // UP-call (+target) 3054 3055 void SbiRuntime::StepGOSUB( sal_uInt32 nOp1 ) 3056 { 3057 PushGosub( pCode ); 3058 if( nOp1 >= pImg->GetCodeSize() ) 3059 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3060 pCode = pImg->GetCode() + nOp1; 3061 } 3062 3063 // UP-return (+0 or target) 3064 3065 void SbiRuntime::StepRETURN( sal_uInt32 nOp1 ) 3066 { 3067 PopGosub(); 3068 if( nOp1 ) 3069 StepJUMP( nOp1 ); 3070 } 3071 3072 // check FOR-variable (+Endlabel) 3073 3074 void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 ) 3075 { 3076 if( !pForStk ) 3077 { 3078 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3079 return; 3080 } 3081 3082 bool bEndLoop = false; 3083 switch( pForStk->eForType ) 3084 { 3085 case ForType::To: 3086 { 3087 SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT; 3088 if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) ) 3089 bEndLoop = true; 3090 if (SbxBase::IsError()) 3091 pForStk->eForType = ForType::Error; // terminate loop at the next iteration 3092 break; 3093 } 3094 case ForType::EachArray: 3095 { 3096 SbiForStack* p = pForStk; 3097 if (!p->refEnd) 3098 { 3099 SbxBase::SetError(ERRCODE_BASIC_CONVERSION); 3100 pForStk->eForType = ForType::Error; // terminate loop at the next iteration 3101 } 3102 else if (p->pArrayCurIndices == nullptr) 3103 { 3104 bEndLoop = true; 3105 } 3106 else 3107 { 3108 SbxDimArray* pArray = reinterpret_cast<SbxDimArray*>(p->refEnd.get()); 3109 sal_Int32 nDims = pArray->GetDims(); 3110 3111 // Empty array? 3112 if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] ) 3113 { 3114 bEndLoop = true; 3115 break; 3116 } 3117 SbxVariable* pVal = pArray->Get(p->pArrayCurIndices.get()); 3118 *(p->refVar) = *pVal; 3119 3120 bool bFoundNext = false; 3121 for(sal_Int32 i = 0 ; i < nDims ; i++ ) 3122 { 3123 if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] ) 3124 { 3125 bFoundNext = true; 3126 p->pArrayCurIndices[i]++; 3127 for( sal_Int32 j = i - 1 ; j >= 0 ; j-- ) 3128 p->pArrayCurIndices[j] = p->pArrayLowerBounds[j]; 3129 break; 3130 } 3131 } 3132 if( !bFoundNext ) 3133 { 3134 p->pArrayCurIndices.reset(); 3135 } 3136 } 3137 break; 3138 } 3139 case ForType::EachCollection: 3140 { 3141 if (!pForStk->refEnd) 3142 { 3143 SbxBase::SetError(ERRCODE_BASIC_CONVERSION); 3144 pForStk->eForType = ForType::Error; // terminate loop at the next iteration 3145 break; 3146 } 3147 3148 BasicCollection* pCollection = static_cast<BasicCollection*>(pForStk->refEnd.get()); 3149 SbxArrayRef xItemArray = pCollection->xItemArray; 3150 sal_Int32 nCount = xItemArray->Count(); 3151 if( pForStk->nCurCollectionIndex < nCount ) 3152 { 3153 SbxVariable* pRes = xItemArray->Get(pForStk->nCurCollectionIndex); 3154 pForStk->nCurCollectionIndex++; 3155 (*pForStk->refVar) = *pRes; 3156 } 3157 else 3158 { 3159 bEndLoop = true; 3160 } 3161 break; 3162 } 3163 case ForType::EachXEnumeration: 3164 { 3165 SbiForStack* p = pForStk; 3166 if (!p->xEnumeration) 3167 { 3168 SbxBase::SetError(ERRCODE_BASIC_CONVERSION); 3169 pForStk->eForType = ForType::Error; // terminate loop at the next iteration 3170 } 3171 else if (p->xEnumeration->hasMoreElements()) 3172 { 3173 Any aElem = p->xEnumeration->nextElement(); 3174 SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); 3175 unoToSbxValue( xVar.get(), aElem ); 3176 (*pForStk->refVar) = *xVar; 3177 } 3178 else 3179 { 3180 bEndLoop = true; 3181 } 3182 break; 3183 } 3184 case ForType::Error: 3185 { 3186 // We are in Resume Next mode after failed loop initialization 3187 bEndLoop = true; 3188 Error(ERRCODE_BASIC_BAD_PARAMETER); 3189 break; 3190 } 3191 } 3192 if( bEndLoop ) 3193 { 3194 PopFor(); 3195 StepJUMP( nOp1 ); 3196 } 3197 } 3198 3199 // Tos+1 <= Tos+2 <= Tos, 2xremove (+Target) 3200 3201 void SbiRuntime::StepCASETO( sal_uInt32 nOp1 ) 3202 { 3203 if (!refCaseStk.is() || !refCaseStk->Count()) 3204 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3205 else 3206 { 3207 SbxVariableRef xTo = PopVar(); 3208 SbxVariableRef xFrom = PopVar(); 3209 SbxVariableRef xCase = refCaseStk->Get(refCaseStk->Count() - 1); 3210 if( *xCase >= *xFrom && *xCase <= *xTo ) 3211 StepJUMP( nOp1 ); 3212 } 3213 } 3214 3215 3216 void SbiRuntime::StepERRHDL( sal_uInt32 nOp1 ) 3217 { 3218 const sal_uInt8* p = pCode; 3219 StepJUMP( nOp1 ); 3220 pError = pCode; 3221 pCode = p; 3222 pInst->aErrorMsg.clear(); 3223 pInst->nErr = ERRCODE_NONE; 3224 pInst->nErl = 0; 3225 nError = ERRCODE_NONE; 3226 SbxErrObject::getUnoErrObject()->Clear(); 3227 } 3228 3229 // Resume after errors (+0=statement, 1=next or Label) 3230 3231 void SbiRuntime::StepRESUME( sal_uInt32 nOp1 ) 3232 { 3233 // #32714 Resume without error? -> error 3234 if( !bInError ) 3235 { 3236 Error( ERRCODE_BASIC_BAD_RESUME ); 3237 return; 3238 } 3239 if( nOp1 ) 3240 { 3241 // set Code-pointer to the next statement 3242 sal_uInt16 n1, n2; 3243 pCode = pMod->FindNextStmnt( pErrCode, n1, n2, true, pImg ); 3244 } 3245 else 3246 pCode = pErrStmnt; 3247 if ( pError ) // current in error handler ( and got a Resume Next statement ) 3248 SbxErrObject::getUnoErrObject()->Clear(); 3249 3250 if( nOp1 > 1 ) 3251 StepJUMP( nOp1 ); 3252 pInst->aErrorMsg.clear(); 3253 pInst->nErr = ERRCODE_NONE; 3254 pInst->nErl = 0; 3255 nError = ERRCODE_NONE; 3256 bInError = false; 3257 } 3258 3259 // close channel (+channel, 0=all) 3260 void SbiRuntime::StepCLOSE( sal_uInt32 nOp1 ) 3261 { 3262 ErrCode err; 3263 if( !nOp1 ) 3264 pIosys->Shutdown(); 3265 else 3266 { 3267 err = pIosys->GetError(); 3268 if( !err ) 3269 { 3270 pIosys->Close(); 3271 } 3272 } 3273 err = pIosys->GetError(); 3274 Error( err ); 3275 } 3276 3277 // output character (+char) 3278 3279 void SbiRuntime::StepPRCHAR( sal_uInt32 nOp1 ) 3280 { 3281 OUString s(static_cast<sal_Unicode>(nOp1)); 3282 pIosys->Write( s ); 3283 Error( pIosys->GetError() ); 3284 } 3285 3286 // check whether TOS is a certain object class (+StringID) 3287 3288 bool SbiRuntime::implIsClass( SbxObject const * pObj, const OUString& aClass ) 3289 { 3290 bool bRet = true; 3291 3292 if( !aClass.isEmpty() ) 3293 { 3294 bRet = pObj->IsClass( aClass ); 3295 if( !bRet ) 3296 bRet = aClass.equalsIgnoreAsciiCase( "object" ); 3297 if( !bRet ) 3298 { 3299 const OUString& aObjClass = pObj->GetClassName(); 3300 SbModule* pClassMod = GetSbData()->pClassFac->FindClass( aObjClass ); 3301 if( pClassMod ) 3302 { 3303 SbClassData* pClassData = pClassMod->pClassData.get(); 3304 if (pClassData != nullptr ) 3305 { 3306 SbxVariable* pClassVar = pClassData->mxIfaces->Find( aClass, SbxClassType::DontCare ); 3307 bRet = (pClassVar != nullptr); 3308 } 3309 } 3310 } 3311 } 3312 return bRet; 3313 } 3314 3315 bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal, 3316 const OUString& aClass, bool bRaiseErrors, bool bDefault ) 3317 { 3318 bool bOk = bDefault; 3319 3320 SbxDataType t = refVal->GetType(); 3321 SbxVariable* pVal = refVal.get(); 3322 // we don't know the type of uno properties that are (maybevoid) 3323 if ( t == SbxEMPTY ) 3324 { 3325 if ( auto pProp = dynamic_cast<SbUnoProperty*>( refVal.get() ) ) 3326 { 3327 t = pProp->getRealType(); 3328 } 3329 } 3330 if( t == SbxOBJECT || bVBAEnabled ) 3331 { 3332 SbxObject* pObj = dynamic_cast<SbxObject*>(pVal); 3333 if (!pObj) 3334 { 3335 pObj = dynamic_cast<SbxObject*>(refVal->GetObject()); 3336 } 3337 if( pObj ) 3338 { 3339 if( !implIsClass( pObj, aClass ) ) 3340 { 3341 SbUnoObject* pUnoObj(nullptr); 3342 if (bVBAEnabled || CodeCompleteOptions::IsExtendedTypeDeclaration()) 3343 { 3344 pUnoObj = dynamic_cast<SbUnoObject*>(pObj); 3345 } 3346 3347 if (pUnoObj) 3348 bOk = checkUnoObjectType(*pUnoObj, aClass); 3349 else 3350 bOk = false; 3351 if ( !bOk && bRaiseErrors ) 3352 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 3353 } 3354 else 3355 { 3356 bOk = true; 3357 3358 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pObj ); 3359 if( pClassModuleObject != nullptr ) 3360 pClassModuleObject->triggerInitializeEvent(); 3361 } 3362 } 3363 } 3364 else 3365 { 3366 if( bRaiseErrors ) 3367 Error( ERRCODE_BASIC_NEEDS_OBJECT ); 3368 bOk = false; 3369 } 3370 return bOk; 3371 } 3372 3373 void SbiRuntime::StepSETCLASS_impl( sal_uInt32 nOp1, bool bHandleDflt ) 3374 { 3375 SbxVariableRef refVal = PopVar(); 3376 SbxVariableRef refVar = PopVar(); 3377 OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); 3378 3379 bool bOk = checkClass_Impl( refVal, aClass, true, true ); 3380 if( bOk ) 3381 { 3382 StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle default prop for a "proper" set 3383 } 3384 } 3385 3386 void SbiRuntime::StepVBASETCLASS( sal_uInt32 nOp1 ) 3387 { 3388 StepSETCLASS_impl( nOp1, false ); 3389 } 3390 3391 void SbiRuntime::StepSETCLASS( sal_uInt32 nOp1 ) 3392 { 3393 StepSETCLASS_impl( nOp1, true ); 3394 } 3395 3396 void SbiRuntime::StepTESTCLASS( sal_uInt32 nOp1 ) 3397 { 3398 SbxVariableRef xObjVal = PopVar(); 3399 OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); 3400 bool bDefault = !bVBAEnabled; 3401 bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault ); 3402 3403 SbxVariable* pRet = new SbxVariable; 3404 pRet->PutBool( bOk ); 3405 PushVar( pRet ); 3406 } 3407 3408 // define library for following declare-call 3409 3410 void SbiRuntime::StepLIB( sal_uInt32 nOp1 ) 3411 { 3412 aLibName = pImg->GetString( static_cast<short>( nOp1 ) ); 3413 } 3414 3415 // TOS is incremented by BASE, BASE is pushed before (+BASE) 3416 // This opcode is pushed before DIM/REDIM-commands, 3417 // if there's been only one index named. 3418 3419 void SbiRuntime::StepBASED( sal_uInt32 nOp1 ) 3420 { 3421 SbxVariable* p1 = new SbxVariable; 3422 SbxVariableRef x2 = PopVar(); 3423 3424 // #109275 Check compatibility mode 3425 bool bCompatible = ((nOp1 & 0x8000) != 0); 3426 sal_uInt16 uBase = static_cast<sal_uInt16>(nOp1 & 1); // Can only be 0 or 1 3427 p1->PutInteger( uBase ); 3428 if( !bCompatible ) 3429 { 3430 // tdf#85371 - grant explicitly write access to the dimension variable 3431 // since in Star/OpenOffice Basic the upper index border is affected, 3432 // and the dimension variable could be the name of the method itself. 3433 ScopedWritableGuard aGuard(x2, x2.get() == pMeth); 3434 x2->Compute( SbxPLUS, *p1 ); 3435 } 3436 PushVar( x2.get() ); // first the Expr 3437 PushVar( p1 ); // then the Base 3438 } 3439 3440 // the bits in the String-ID: 3441 // 0x8000 - Argv is reserved 3442 3443 SbxVariable* SbiRuntime::FindElement( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2, 3444 ErrCode nNotFound, bool bLocal, bool bStatic ) 3445 { 3446 bool bIsVBAInterOp = SbiRuntime::isVBAEnabled(); 3447 if( bIsVBAInterOp ) 3448 { 3449 StarBASIC* pMSOMacroRuntimeLib = GetSbData()->pMSOMacroRuntimLib; 3450 if( pMSOMacroRuntimeLib != nullptr ) 3451 { 3452 pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::ExtSearch ); 3453 } 3454 } 3455 3456 SbxVariable* pElem = nullptr; 3457 if( !pObj ) 3458 { 3459 Error( ERRCODE_BASIC_NO_OBJECT ); 3460 pElem = new SbxVariable; 3461 } 3462 else 3463 { 3464 bool bFatalError = false; 3465 SbxDataType t = static_cast<SbxDataType>(nOp2); 3466 OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); 3467 // Hacky capture of Evaluate [] syntax 3468 // this should be tackled I feel at the pcode level 3469 if ( bIsVBAInterOp && aName.startsWith("[") ) 3470 { 3471 // emulate pcode here 3472 StepARGC(); 3473 // pseudo StepLOADSC 3474 OUString sArg = aName.copy( 1, aName.getLength() - 2 ); 3475 SbxVariable* p = new SbxVariable; 3476 p->PutString( sArg ); 3477 PushVar( p ); 3478 StepARGV(); 3479 nOp1 = nOp1 | 0x8000; // indicate params are present 3480 aName = "Evaluate"; 3481 } 3482 if( bLocal ) 3483 { 3484 if ( bStatic && pMeth ) 3485 { 3486 pElem = pMeth->GetStatics()->Find( aName, SbxClassType::DontCare ); 3487 } 3488 3489 if ( !pElem ) 3490 { 3491 pElem = refLocals->Find( aName, SbxClassType::DontCare ); 3492 } 3493 } 3494 if( !pElem ) 3495 { 3496 bool bSave = rBasic.bNoRtl; 3497 rBasic.bNoRtl = true; 3498 pElem = pObj->Find( aName, SbxClassType::DontCare ); 3499 3500 // #110004, #112015: Make private really private 3501 if( bLocal && pElem ) // Local as flag for global search 3502 { 3503 if( pElem->IsSet( SbxFlagBits::Private ) ) 3504 { 3505 SbiInstance* pInst_ = GetSbData()->pInst; 3506 if( pInst_ && pInst_->IsCompatibility() && pObj != pElem->GetParent() ) 3507 { 3508 pElem = nullptr; // Found but in wrong module! 3509 } 3510 // Interfaces: Use SbxFlagBits::ExtFound 3511 } 3512 } 3513 rBasic.bNoRtl = bSave; 3514 3515 // is it a global uno-identifier? 3516 if( bLocal && !pElem ) 3517 { 3518 bool bSetName = true; // preserve normal behaviour 3519 3520 // i#i68894# if VBAInterOp favour searching vba globals 3521 // over searching for uno classes 3522 if ( bVBAEnabled ) 3523 { 3524 // Try Find in VBA symbols space 3525 pElem = rBasic.VBAFind( aName, SbxClassType::DontCare ); 3526 if ( pElem ) 3527 { 3528 bSetName = false; // don't overwrite uno name 3529 } 3530 else 3531 { 3532 pElem = VBAConstantHelper::instance().getVBAConstant( aName ); 3533 } 3534 } 3535 3536 if( !pElem ) 3537 { 3538 // #72382 ATTENTION! ALWAYS returns a result now 3539 // because of unknown modules! 3540 SbUnoClass* pUnoClass = findUnoClass( aName ); 3541 if( pUnoClass ) 3542 { 3543 pElem = new SbxVariable( t ); 3544 SbxValues aRes( SbxOBJECT ); 3545 aRes.pObj = pUnoClass; 3546 pElem->SbxVariable::Put( aRes ); 3547 } 3548 } 3549 3550 // #62939 If a uno-class has been found, the wrapper 3551 // object has to be held, because the uno-class, e. g. 3552 // "stardiv", has to be read out of the registry 3553 // every time again otherwise 3554 if( pElem ) 3555 { 3556 // #63774 May not be saved too!!! 3557 pElem->SetFlag( SbxFlagBits::DontStore ); 3558 pElem->SetFlag( SbxFlagBits::NoModify); 3559 3560 // #72382 save locally, all variables that have been declared 3561 // implicit would become global automatically otherwise! 3562 if ( bSetName ) 3563 { 3564 pElem->SetName( aName ); 3565 } 3566 refLocals->Put(pElem, refLocals->Count()); 3567 } 3568 } 3569 3570 if( !pElem ) 3571 { 3572 // not there and not in the object? 3573 // don't establish if that thing has parameters! 3574 if( nOp1 & 0x8000 ) 3575 { 3576 bFatalError = true; 3577 } 3578 3579 // else, if there are parameters, use different error code 3580 if( !bLocal || pImg->IsFlag( SbiImageFlags::EXPLICIT ) ) 3581 { 3582 // #39108 if explicit and as ELEM always a fatal error 3583 bFatalError = true; 3584 3585 3586 if( !( nOp1 & 0x8000 ) && nNotFound == ERRCODE_BASIC_PROC_UNDEFINED ) 3587 { 3588 nNotFound = ERRCODE_BASIC_VAR_UNDEFINED; 3589 } 3590 } 3591 if( bFatalError ) 3592 { 3593 // #39108 use dummy variable instead of fatal error 3594 if( !xDummyVar.is() ) 3595 { 3596 xDummyVar = new SbxVariable( SbxVARIANT ); 3597 } 3598 pElem = xDummyVar.get(); 3599 3600 ClearArgvStack(); 3601 3602 Error( nNotFound, aName ); 3603 } 3604 else 3605 { 3606 if ( bStatic ) 3607 { 3608 pElem = StepSTATIC_Impl( aName, t, 0 ); 3609 } 3610 if ( !pElem ) 3611 { 3612 pElem = new SbxVariable( t ); 3613 if( t != SbxVARIANT ) 3614 { 3615 pElem->SetFlag( SbxFlagBits::Fixed ); 3616 } 3617 pElem->SetName( aName ); 3618 refLocals->Put(pElem, refLocals->Count()); 3619 } 3620 } 3621 } 3622 } 3623 // #39108 Args can already be deleted! 3624 if( !bFatalError ) 3625 { 3626 SetupArgs( pElem, nOp1 ); 3627 } 3628 // because a particular call-type is requested 3629 if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pElem)) 3630 { 3631 // shall the type be converted? 3632 SbxDataType t2 = pElem->GetType(); 3633 bool bSet = false; 3634 if( (pElem->GetFlags() & SbxFlagBits::Fixed) == SbxFlagBits::NONE ) 3635 { 3636 if( t != SbxVARIANT && t != t2 && 3637 t >= SbxINTEGER && t <= SbxSTRING ) 3638 { 3639 pElem->SetType( t ); 3640 bSet = true; 3641 } 3642 } 3643 // assign pElem to a Ref, to delete a temp-var if applicable 3644 SbxVariableRef xDeleteRef = pElem; 3645 3646 // remove potential rests of the last call of the SbxMethod 3647 // free Write before, so that there's no error 3648 SbxFlagBits nSavFlags = pElem->GetFlags(); 3649 pElem->SetFlag( SbxFlagBits::ReadWrite | SbxFlagBits::NoBroadcast ); 3650 pElem->SbxValue::Clear(); 3651 pElem->SetFlags( nSavFlags ); 3652 3653 // don't touch before setting, as e. g. LEFT() 3654 // has to know the difference between Left$() and Left() 3655 3656 // because the methods' parameters are cut away in PopVar() 3657 SbxVariable* pNew = new SbxMethod(*pMethod); 3658 //OLD: SbxVariable* pNew = new SbxVariable( *pElem ); 3659 3660 pElem->SetParameters(nullptr); 3661 pNew->SetFlag( SbxFlagBits::ReadWrite ); 3662 3663 if( bSet ) 3664 { 3665 pElem->SetType( t2 ); 3666 } 3667 pElem = pNew; 3668 } 3669 // consider index-access for UnoObjects 3670 // definitely we want this for VBA where properties are often 3671 // collections ( which need index access ), but lets only do 3672 // this if we actually have params following 3673 else if( bVBAEnabled && dynamic_cast<const SbUnoProperty*>( pElem) != nullptr && pElem->GetParameters() ) 3674 { 3675 SbxVariableRef xDeleteRef = pElem; 3676 3677 // dissolve the notify while copying variable 3678 SbxVariable* pNew = new SbxVariable( *pElem ); 3679 pElem->SetParameters( nullptr ); 3680 pElem = pNew; 3681 } 3682 } 3683 return CheckArray( pElem ); 3684 } 3685 3686 // for current scope (e. g. query from BASIC-IDE) 3687 SbxBase* SbiRuntime::FindElementExtern( const OUString& rName ) 3688 { 3689 // don't expect pMeth to be != 0, as there are none set 3690 // in the RunInit yet 3691 3692 SbxVariable* pElem = nullptr; 3693 if( !pMod || rName.isEmpty() ) 3694 { 3695 return nullptr; 3696 } 3697 if( refLocals.is() ) 3698 { 3699 pElem = refLocals->Find( rName, SbxClassType::DontCare ); 3700 } 3701 if ( !pElem && pMeth ) 3702 { 3703 // for statics, set the method's name in front 3704 OUString aMethName = pMeth->GetName() + ":" + rName; 3705 pElem = pMod->Find(aMethName, SbxClassType::DontCare); 3706 } 3707 3708 // search in parameter list 3709 if( !pElem && pMeth ) 3710 { 3711 SbxInfo* pInfo = pMeth->GetInfo(); 3712 if( pInfo && refParams.is() ) 3713 { 3714 sal_uInt32 nParamCount = refParams->Count(); 3715 assert(nParamCount <= std::numeric_limits<sal_uInt16>::max()); 3716 sal_uInt16 j = 1; 3717 const SbxParamInfo* pParam = pInfo->GetParam( j ); 3718 while( pParam ) 3719 { 3720 if( pParam->aName.equalsIgnoreAsciiCase( rName ) ) 3721 { 3722 if( j >= nParamCount ) 3723 { 3724 // Parameter is missing 3725 pElem = new SbxVariable( SbxSTRING ); 3726 pElem->PutString( "<missing parameter>"); 3727 } 3728 else 3729 { 3730 pElem = refParams->Get(j); 3731 } 3732 break; 3733 } 3734 pParam = pInfo->GetParam( ++j ); 3735 } 3736 } 3737 } 3738 3739 // search in module 3740 if( !pElem ) 3741 { 3742 bool bSave = rBasic.bNoRtl; 3743 rBasic.bNoRtl = true; 3744 pElem = pMod->Find( rName, SbxClassType::DontCare ); 3745 rBasic.bNoRtl = bSave; 3746 } 3747 return pElem; 3748 } 3749 3750 3751 void SbiRuntime::SetupArgs( SbxVariable* p, sal_uInt32 nOp1 ) 3752 { 3753 if( nOp1 & 0x8000 ) 3754 { 3755 if( !refArgv.is() ) 3756 { 3757 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3758 } 3759 bool bHasNamed = false; 3760 sal_uInt32 i; 3761 sal_uInt32 nArgCount = refArgv->Count(); 3762 for( i = 1 ; i < nArgCount ; i++ ) 3763 { 3764 if (!refArgv->GetAlias(i).isEmpty()) 3765 { 3766 bHasNamed = true; break; 3767 } 3768 } 3769 if( bHasNamed ) 3770 { 3771 SbxInfo* pInfo = p->GetInfo(); 3772 if( !pInfo ) 3773 { 3774 bool bError_ = true; 3775 3776 SbUnoMethod* pUnoMethod = dynamic_cast<SbUnoMethod*>( p ); 3777 SbUnoProperty* pUnoProperty = dynamic_cast<SbUnoProperty*>( p ); 3778 if( pUnoMethod || pUnoProperty ) 3779 { 3780 SbUnoObject* pParentUnoObj = dynamic_cast<SbUnoObject*>( p->GetParent() ); 3781 if( pParentUnoObj ) 3782 { 3783 Any aUnoAny = pParentUnoObj->getUnoAny(); 3784 Reference< XInvocation > xInvocation; 3785 aUnoAny >>= xInvocation; 3786 if( xInvocation.is() ) // TODO: if( xOLEAutomation.is() ) 3787 { 3788 bError_ = false; 3789 3790 sal_uInt32 nCurPar = 1; 3791 AutomationNamedArgsSbxArray* pArg = 3792 new AutomationNamedArgsSbxArray( nArgCount ); 3793 OUString* pNames = pArg->getNames().getArray(); 3794 for( i = 1 ; i < nArgCount ; i++ ) 3795 { 3796 SbxVariable* pVar = refArgv->Get(i); 3797 OUString aName = refArgv->GetAlias(i); 3798 if (!aName.isEmpty()) 3799 { 3800 pNames[i] = aName; 3801 } 3802 pArg->Put(pVar, nCurPar++); 3803 } 3804 refArgv = pArg; 3805 } 3806 } 3807 } 3808 else if( bVBAEnabled && p->GetType() == SbxOBJECT && (dynamic_cast<const SbxMethod*>( p) == nullptr || !p->IsBroadcaster()) ) 3809 { 3810 // Check for default method with named parameters 3811 SbxBaseRef xObj = p->GetObject(); 3812 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( xObj.get() )) 3813 { 3814 Any aAny = pUnoObj->getUnoAny(); 3815 3816 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 3817 { 3818 Reference< XDefaultMethod > xDfltMethod( aAny, UNO_QUERY ); 3819 3820 OUString sDefaultMethod; 3821 if ( xDfltMethod.is() ) 3822 { 3823 sDefaultMethod = xDfltMethod->getDefaultMethodName(); 3824 } 3825 if ( !sDefaultMethod.isEmpty() ) 3826 { 3827 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method ); 3828 if( meth != nullptr ) 3829 { 3830 pInfo = meth->GetInfo(); 3831 } 3832 if( pInfo ) 3833 { 3834 bError_ = false; 3835 } 3836 } 3837 } 3838 } 3839 } 3840 if( bError_ ) 3841 { 3842 Error( ERRCODE_BASIC_NO_NAMED_ARGS ); 3843 } 3844 } 3845 else 3846 { 3847 sal_uInt32 nCurPar = 1; 3848 SbxArray* pArg = new SbxArray; 3849 for( i = 1 ; i < nArgCount ; i++ ) 3850 { 3851 SbxVariable* pVar = refArgv->Get(i); 3852 OUString aName = refArgv->GetAlias(i); 3853 if (!aName.isEmpty()) 3854 { 3855 // nCurPar is set to the found parameter 3856 sal_uInt16 j = 1; 3857 const SbxParamInfo* pParam = pInfo->GetParam( j ); 3858 while( pParam ) 3859 { 3860 if( pParam->aName.equalsIgnoreAsciiCase( aName ) ) 3861 { 3862 nCurPar = j; 3863 break; 3864 } 3865 pParam = pInfo->GetParam( ++j ); 3866 } 3867 if( !pParam ) 3868 { 3869 Error( ERRCODE_BASIC_NAMED_NOT_FOUND ); break; 3870 } 3871 } 3872 pArg->Put(pVar, nCurPar++); 3873 } 3874 refArgv = pArg; 3875 } 3876 } 3877 // own var as parameter 0 3878 refArgv->Put(p, 0); 3879 p->SetParameters( refArgv.get() ); 3880 PopArgv(); 3881 } 3882 else 3883 { 3884 p->SetParameters( nullptr ); 3885 } 3886 } 3887 3888 // getting an array element 3889 3890 SbxVariable* SbiRuntime::CheckArray( SbxVariable* pElem ) 3891 { 3892 SbxArray* pPar; 3893 if( ( pElem->GetType() & SbxARRAY ) && refRedim.get() != pElem ) 3894 { 3895 SbxBase* pElemObj = pElem->GetObject(); 3896 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 3897 pPar = pElem->GetParameters(); 3898 if( pDimArray ) 3899 { 3900 // parameters may be missing, if an array is 3901 // passed as an argument 3902 if( pPar ) 3903 pElem = pDimArray->Get( pPar ); 3904 } 3905 else 3906 { 3907 SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj ); 3908 if( pArray ) 3909 { 3910 if( !pPar ) 3911 { 3912 Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3913 pElem = new SbxVariable; 3914 } 3915 else 3916 { 3917 pElem = pArray->Get(pPar->Get(1)->GetInteger()); 3918 } 3919 } 3920 } 3921 3922 // #42940, set parameter 0 to NULL so that var doesn't contain itself 3923 if( pPar ) 3924 { 3925 pPar->Put(nullptr, 0); 3926 } 3927 } 3928 // consider index-access for UnoObjects 3929 else if( pElem->GetType() == SbxOBJECT && 3930 dynamic_cast<const SbxMethod*>( pElem) == nullptr && 3931 ( !bVBAEnabled || dynamic_cast<const SbxProperty*>( pElem) == nullptr ) ) 3932 { 3933 pPar = pElem->GetParameters(); 3934 if ( pPar ) 3935 { 3936 // is it a uno-object? 3937 SbxBaseRef pObj = pElem->GetObject(); 3938 if( pObj.is() ) 3939 { 3940 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj.get())) 3941 { 3942 Any aAny = pUnoObj->getUnoAny(); 3943 3944 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 3945 { 3946 Reference< XIndexAccess > xIndexAccess( aAny, UNO_QUERY ); 3947 if ( !bVBAEnabled ) 3948 { 3949 if( xIndexAccess.is() ) 3950 { 3951 sal_uInt32 nParamCount = pPar->Count() - 1; 3952 if( nParamCount != 1 ) 3953 { 3954 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3955 return pElem; 3956 } 3957 3958 // get index 3959 sal_Int32 nIndex = pPar->Get(1)->GetLong(); 3960 Reference< XInterface > xRet; 3961 try 3962 { 3963 Any aAny2 = xIndexAccess->getByIndex( nIndex ); 3964 aAny2 >>= xRet; 3965 } 3966 catch (const IndexOutOfBoundsException&) 3967 { 3968 // usually expect converting problem 3969 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3970 } 3971 3972 // #57847 always create a new variable, else error 3973 // due to PutObject(NULL) at ReadOnly-properties 3974 pElem = new SbxVariable( SbxVARIANT ); 3975 if( xRet.is() ) 3976 { 3977 aAny <<= xRet; 3978 3979 // #67173 don't specify a name so that the real class name is entered 3980 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoObject( OUString(), aAny )); 3981 pElem->PutObject( xWrapper.get() ); 3982 } 3983 else 3984 { 3985 pElem->PutObject( nullptr ); 3986 } 3987 } 3988 } 3989 else 3990 { 3991 // check if there isn't a default member between the current variable 3992 // and the params, e.g. 3993 // Dim rst1 As New ADODB.Recordset 3994 // " 3995 // val = rst1("FirstName") 3996 // has the default 'Fields' member between rst1 and '("FirstName")' 3997 Any x = aAny; 3998 SbxVariable* pDflt = getDefaultProp( pElem ); 3999 if ( pDflt ) 4000 { 4001 pDflt->Broadcast( SfxHintId::BasicDataWanted ); 4002 SbxBaseRef pDfltObj = pDflt->GetObject(); 4003 if( pDfltObj.is() ) 4004 { 4005 if (SbUnoObject* pSbObj = dynamic_cast<SbUnoObject*>(pDfltObj.get())) 4006 { 4007 pUnoObj = pSbObj; 4008 Any aUnoAny = pUnoObj->getUnoAny(); 4009 4010 if( aUnoAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 4011 x = aUnoAny; 4012 pElem = pDflt; 4013 } 4014 } 4015 } 4016 OUString sDefaultMethod; 4017 4018 Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY ); 4019 4020 if ( xDfltMethod.is() ) 4021 { 4022 sDefaultMethod = xDfltMethod->getDefaultMethodName(); 4023 } 4024 else if( xIndexAccess.is() ) 4025 { 4026 sDefaultMethod = "getByIndex"; 4027 } 4028 if ( !sDefaultMethod.isEmpty() ) 4029 { 4030 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method ); 4031 SbxVariableRef refTemp = meth; 4032 if ( refTemp.is() ) 4033 { 4034 meth->SetParameters( pPar ); 4035 SbxVariable* pNew = new SbxMethod( *static_cast<SbxMethod*>(meth) ); 4036 pElem = pNew; 4037 } 4038 } 4039 } 4040 } 4041 4042 // #42940, set parameter 0 to NULL so that var doesn't contain itself 4043 pPar->Put(nullptr, 0); 4044 } 4045 else if (BasicCollection* pCol = dynamic_cast<BasicCollection*>(pObj.get())) 4046 { 4047 pElem = new SbxVariable( SbxVARIANT ); 4048 pPar->Put(pElem, 0); 4049 pCol->CollItem( pPar ); 4050 } 4051 } 4052 else if( bVBAEnabled ) // !pObj 4053 { 4054 SbxArray* pParam = pElem->GetParameters(); 4055 if( pParam != nullptr && !pElem->IsSet( SbxFlagBits::VarToDim ) ) 4056 { 4057 Error( ERRCODE_BASIC_NO_OBJECT ); 4058 } 4059 } 4060 } 4061 } 4062 4063 return pElem; 4064 } 4065 4066 // loading an element from the runtime-library (+StringID+type) 4067 4068 void SbiRuntime::StepRTL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4069 { 4070 PushVar( FindElement( rBasic.pRtl.get(), nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, false ) ); 4071 } 4072 4073 void SbiRuntime::StepFIND_Impl( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2, 4074 ErrCode nNotFound, bool bStatic ) 4075 { 4076 if( !refLocals.is() ) 4077 { 4078 refLocals = new SbxArray; 4079 } 4080 PushVar( FindElement( pObj, nOp1, nOp2, nNotFound, true/*bLocal*/, bStatic ) ); 4081 } 4082 // loading a local/global variable (+StringID+type) 4083 4084 void SbiRuntime::StepFIND( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4085 { 4086 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED ); 4087 } 4088 4089 // Search inside a class module (CM) to enable global search in time 4090 void SbiRuntime::StepFIND_CM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4091 { 4092 4093 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pMod ); 4094 if( pClassModuleObject ) 4095 { 4096 pMod->SetFlag( SbxFlagBits::GlobalSearch ); 4097 } 4098 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED); 4099 4100 if( pClassModuleObject ) 4101 { 4102 pMod->ResetFlag( SbxFlagBits::GlobalSearch ); 4103 } 4104 } 4105 4106 void SbiRuntime::StepFIND_STATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4107 { 4108 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, true ); 4109 } 4110 4111 // loading an object-element (+StringID+type) 4112 // the object lies on TOS 4113 4114 void SbiRuntime::StepELEM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4115 { 4116 SbxVariableRef pObjVar = PopVar(); 4117 4118 SbxObject* pObj = dynamic_cast<SbxObject*>( pObjVar.get() ); 4119 if( !pObj ) 4120 { 4121 SbxBase* pObjVarObj = pObjVar->GetObject(); 4122 pObj = dynamic_cast<SbxObject*>( pObjVarObj ); 4123 } 4124 4125 // #56368 save reference at StepElem, otherwise objects could 4126 // lose their reference too early in qualification chains like 4127 // ActiveComponent.Selection(0).Text 4128 // #74254 now per list 4129 if( pObj ) 4130 { 4131 aRefSaved.emplace_back(pObj ); 4132 } 4133 PushVar( FindElement( pObj, nOp1, nOp2, ERRCODE_BASIC_NO_METHOD, false ) ); 4134 } 4135 4136 /** Loading of a parameter (+offset+type) 4137 If the data type is wrong, create a copy and search for optionals including 4138 the default value. The data type SbxEMPTY shows that no parameters are given. 4139 Get( 0 ) may be EMPTY 4140 4141 @param nOp1 4142 the index of the current parameter being processed, 4143 where the entry of the index 0 is for the return value. 4144 4145 @param nOp2 4146 the data type of the parameter. 4147 */ 4148 void SbiRuntime::StepPARAM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4149 { 4150 sal_uInt16 nIdx = static_cast<sal_uInt16>( nOp1 & 0x7FFF ); 4151 SbxDataType eType = static_cast<SbxDataType>(nOp2); 4152 SbxVariable* pVar; 4153 4154 // #57915 solve missing in a cleaner way 4155 sal_uInt32 nParamCount = refParams->Count(); 4156 if( nIdx >= nParamCount ) 4157 { 4158 sal_uInt16 iLoop = nIdx; 4159 while( iLoop >= nParamCount ) 4160 { 4161 pVar = new SbxVariable(); 4162 pVar->PutErr( 448 ); // like in VB: Error-Code 448 (ERRCODE_BASIC_NAMED_NOT_FOUND) 4163 // tdf#79426, tdf#125180 - add additional information about a missing parameter 4164 SetIsMissing( pVar ); 4165 refParams->Put(pVar, iLoop); 4166 iLoop--; 4167 } 4168 } 4169 pVar = refParams->Get(nIdx); 4170 4171 // tdf#79426, tdf#125180 - check for optionals only if the parameter is actually missing 4172 if( pVar->GetType() == SbxERROR && IsMissing( pVar, 1 ) && nIdx ) 4173 { 4174 // if there's a parameter missing, it can be OPTIONAL 4175 bool bOpt = false; 4176 if( pMeth ) 4177 { 4178 SbxInfo* pInfo = pMeth->GetInfo(); 4179 if ( pInfo ) 4180 { 4181 const SbxParamInfo* pParam = pInfo->GetParam( nIdx ); 4182 if( pParam && ( pParam->nFlags & SbxFlagBits::Optional ) ) 4183 { 4184 // tdf#136143 - reset SbxFlagBits::Fixed in order to prevent type conversion errors 4185 pVar->ResetFlag( SbxFlagBits::Fixed ); 4186 // Default value? 4187 sal_uInt16 nDefaultId = static_cast<sal_uInt16>(pParam->nUserData & 0x0ffff); 4188 if( nDefaultId > 0 ) 4189 { 4190 // tdf#143707 - check if the data type character was added after the string 4191 // termination symbol, and convert the variable if it was present. The 4192 // data type character was It was added in basic/source/comp/symtbl.cxx. 4193 SbxDataType eTypeStr; 4194 OUString aDefaultStr = pImg->GetString( nDefaultId, &eTypeStr ); 4195 pVar = new SbxVariable(pParam-> eType); 4196 pVar->PutString( aDefaultStr ); 4197 if (eTypeStr != SbxSTRING) 4198 pVar->Convert(eTypeStr); 4199 refParams->Put(pVar, nIdx); 4200 } 4201 else if ( SbiRuntime::isVBAEnabled() && eType != SbxVARIANT ) 4202 { 4203 // tdf#36737 - initialize the parameter with the default value of its type 4204 pVar = new SbxVariable( pParam->eType ); 4205 refParams->Put(pVar, nIdx); 4206 } 4207 bOpt = true; 4208 } 4209 } 4210 } 4211 if( !bOpt ) 4212 { 4213 Error( ERRCODE_BASIC_NOT_OPTIONAL ); 4214 } 4215 } 4216 else if( eType != SbxVARIANT && static_cast<SbxDataType>(pVar->GetType() & 0x0FFF ) != eType ) 4217 { 4218 // tdf#43003 - convert parameter to the requested type 4219 pVar->Convert(eType); 4220 } 4221 SetupArgs( pVar, nOp1 ); 4222 PushVar( CheckArray( pVar ) ); 4223 } 4224 4225 // Case-Test (+True-Target+Test-Opcode) 4226 4227 void SbiRuntime::StepCASEIS( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4228 { 4229 if (!refCaseStk.is() || !refCaseStk->Count()) 4230 { 4231 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 4232 } 4233 else 4234 { 4235 SbxVariableRef xComp = PopVar(); 4236 SbxVariableRef xCase = refCaseStk->Get(refCaseStk->Count() - 1); 4237 if( xCase->Compare( static_cast<SbxOperator>(nOp2), *xComp ) ) 4238 { 4239 StepJUMP( nOp1 ); 4240 } 4241 } 4242 } 4243 4244 // call of a DLL-procedure (+StringID+type) 4245 // the StringID's MSB shows that Argv is occupied 4246 4247 void SbiRuntime::StepCALL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4248 { 4249 OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); 4250 SbxArray* pArgs = nullptr; 4251 if( nOp1 & 0x8000 ) 4252 { 4253 pArgs = refArgv.get(); 4254 } 4255 DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), false ); 4256 aLibName.clear(); 4257 if( nOp1 & 0x8000 ) 4258 { 4259 PopArgv(); 4260 } 4261 } 4262 4263 // call of a DLL-procedure after CDecl (+StringID+type) 4264 4265 void SbiRuntime::StepCALLC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4266 { 4267 OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); 4268 SbxArray* pArgs = nullptr; 4269 if( nOp1 & 0x8000 ) 4270 { 4271 pArgs = refArgv.get(); 4272 } 4273 DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), true ); 4274 aLibName.clear(); 4275 if( nOp1 & 0x8000 ) 4276 { 4277 PopArgv(); 4278 } 4279 } 4280 4281 4282 // beginning of a statement (+Line+Col) 4283 4284 void SbiRuntime::StepSTMNT( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4285 { 4286 // If the Expr-Stack at the beginning of a statement contains a variable, 4287 // some fool has called X as a function, although it's a variable! 4288 bool bFatalExpr = false; 4289 OUString sUnknownMethodName; 4290 if( nExprLvl > 1 ) 4291 { 4292 bFatalExpr = true; 4293 } 4294 else if( nExprLvl ) 4295 { 4296 SbxVariable* p = refExprStk->Get(0); 4297 if( p->GetRefCount() > 1 && 4298 refLocals.is() && refLocals->Find( p->GetName(), p->GetClass() ) ) 4299 { 4300 sUnknownMethodName = p->GetName(); 4301 bFatalExpr = true; 4302 } 4303 } 4304 4305 ClearExprStack(); 4306 4307 aRefSaved.clear(); 4308 4309 // We have to cancel hard here because line and column 4310 // would be wrong later otherwise! 4311 if( bFatalExpr) 4312 { 4313 StarBASIC::FatalError( ERRCODE_BASIC_NO_METHOD, sUnknownMethodName ); 4314 return; 4315 } 4316 pStmnt = pCode - 9; 4317 sal_uInt16 nOld = nLine; 4318 nLine = static_cast<short>( nOp1 ); 4319 4320 // #29955 & 0xFF, to filter out for-loop-level 4321 nCol1 = static_cast<short>( nOp2 & 0xFF ); 4322 4323 // find the next STMNT-command to set the final column 4324 // of this statement 4325 4326 nCol2 = 0xffff; 4327 sal_uInt16 n1, n2; 4328 const sal_uInt8* p = pMod->FindNextStmnt( pCode, n1, n2 ); 4329 if( p ) 4330 { 4331 if( n1 == nOp1 ) 4332 { 4333 // #29955 & 0xFF, to filter out for-loop-level 4334 nCol2 = (n2 & 0xFF) - 1; 4335 } 4336 } 4337 4338 // #29955 correct for-loop-level, #67452 NOT in the error-handler 4339 if( !bInError ) 4340 { 4341 // (there's a difference here in case of a jump out of a loop) 4342 sal_uInt16 nExpectedForLevel = static_cast<sal_uInt16>( nOp2 / 0x100 ); 4343 if( !pGosubStk.empty() ) 4344 { 4345 nExpectedForLevel = nExpectedForLevel + pGosubStk.back().nStartForLvl; 4346 } 4347 4348 // if the actual for-level is too small it'd jump out 4349 // of a loop -> corrected 4350 while( nForLvl > nExpectedForLevel ) 4351 { 4352 PopFor(); 4353 } 4354 } 4355 4356 // 16.10.96: #31460 new concept for StepInto/Over/Out 4357 // see explanation at _ImplGetBreakCallLevel 4358 if( pInst->nCallLvl <= pInst->nBreakCallLvl ) 4359 { 4360 StarBASIC* pStepBasic = GetCurrentBasic( &rBasic ); 4361 BasicDebugFlags nNewFlags = pStepBasic->StepPoint( nLine, nCol1, nCol2 ); 4362 4363 pInst->CalcBreakCallLevel( nNewFlags ); 4364 } 4365 4366 // break points only at STMNT-commands in a new line! 4367 else if( ( nOp1 != nOld ) 4368 && ( nFlags & BasicDebugFlags::Break ) 4369 && pMod->IsBP( static_cast<sal_uInt16>( nOp1 ) ) ) 4370 { 4371 StarBASIC* pBreakBasic = GetCurrentBasic( &rBasic ); 4372 BasicDebugFlags nNewFlags = pBreakBasic->BreakPoint( nLine, nCol1, nCol2 ); 4373 4374 pInst->CalcBreakCallLevel( nNewFlags ); 4375 } 4376 } 4377 4378 // (+StreamMode+Flags) 4379 // Stack: block length 4380 // channel number 4381 // file name 4382 4383 void SbiRuntime::StepOPEN( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4384 { 4385 SbxVariableRef pName = PopVar(); 4386 SbxVariableRef pChan = PopVar(); 4387 SbxVariableRef pLen = PopVar(); 4388 short nBlkLen = pLen->GetInteger(); 4389 short nChan = pChan->GetInteger(); 4390 OString aName(OUStringToOString(pName->GetOUString(), osl_getThreadTextEncoding())); 4391 pIosys->Open( nChan, aName, static_cast<StreamMode>( nOp1 ), 4392 static_cast<SbiStreamFlags>( nOp2 ), nBlkLen ); 4393 Error( pIosys->GetError() ); 4394 } 4395 4396 // create object (+StringID+StringID) 4397 4398 void SbiRuntime::StepCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4399 { 4400 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4401 SbxObjectRef pObj = SbxBase::CreateObject( aClass ); 4402 if( !pObj ) 4403 { 4404 Error( ERRCODE_BASIC_INVALID_OBJECT ); 4405 } 4406 else 4407 { 4408 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4409 pObj->SetName( aName ); 4410 // the object must be able to call the BASIC 4411 pObj->SetParent( &rBasic ); 4412 SbxVariableRef pNew = new SbxVariable; 4413 pNew->PutObject( pObj.get() ); 4414 PushVar( pNew.get() ); 4415 } 4416 } 4417 4418 void SbiRuntime::StepDCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4419 { 4420 StepDCREATE_IMPL( nOp1, nOp2 ); 4421 } 4422 4423 void SbiRuntime::StepDCREATE_REDIMP( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4424 { 4425 StepDCREATE_IMPL( nOp1, nOp2 ); 4426 } 4427 4428 // #56204 create object array (+StringID+StringID), DCREATE == Dim-Create 4429 void SbiRuntime::StepDCREATE_IMPL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4430 { 4431 SbxVariableRef refVar = PopVar(); 4432 4433 DimImpl( refVar ); 4434 4435 // fill the array with instances of the requested class 4436 SbxBase* pObj = refVar->GetObject(); 4437 if (!pObj) 4438 { 4439 StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT ); 4440 return; 4441 } 4442 4443 SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(pObj); 4444 if (!pArray) 4445 return; 4446 4447 const sal_Int32 nDims = pArray->GetDims(); 4448 sal_Int32 nTotalSize = nDims > 0 ? 1 : 0; 4449 4450 // must be a one-dimensional array 4451 sal_Int32 nLower, nUpper; 4452 for( sal_Int32 i = 0 ; i < nDims ; ++i ) 4453 { 4454 pArray->GetDim(i + 1, nLower, nUpper); 4455 const sal_Int32 nSize = nUpper - nLower + 1; 4456 nTotalSize *= nSize; 4457 } 4458 4459 // Optimization: pre-allocate underlying container 4460 if (nTotalSize > 0) 4461 pArray->SbxArray::GetRef(nTotalSize - 1); 4462 4463 // First, fill those parts of the array that are preserved 4464 bool bWasError = false; 4465 const bool bRestored = implRestorePreservedArray(pArray, refRedimpArray, &bWasError); 4466 if (bWasError) 4467 nTotalSize = 0; // on error, don't create objects 4468 4469 // create objects and insert them into the array 4470 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4471 OUString aName; 4472 for( sal_Int32 i = 0 ; i < nTotalSize ; ++i ) 4473 { 4474 if (!bRestored || !pArray->SbxArray::GetRef(i)) // For those left unset after preserve 4475 { 4476 SbxObjectRef pClassObj = SbxBase::CreateObject(aClass); 4477 if (!pClassObj) 4478 { 4479 Error(ERRCODE_BASIC_INVALID_OBJECT); 4480 break; 4481 } 4482 else 4483 { 4484 if (aName.isEmpty()) 4485 aName = pImg->GetString(static_cast<short>(nOp1)); 4486 pClassObj->SetName(aName); 4487 // the object must be able to call the basic 4488 pClassObj->SetParent(&rBasic); 4489 pArray->SbxArray::Put(pClassObj.get(), i); 4490 } 4491 } 4492 } 4493 } 4494 4495 void SbiRuntime::StepTCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4496 { 4497 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4498 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4499 4500 SbxObjectRef pCopyObj = createUserTypeImpl( aClass ); 4501 if( pCopyObj ) 4502 { 4503 pCopyObj->SetName( aName ); 4504 } 4505 SbxVariableRef pNew = new SbxVariable; 4506 pNew->PutObject( pCopyObj.get() ); 4507 pNew->SetDeclareClassName( aClass ); 4508 PushVar( pNew.get() ); 4509 } 4510 4511 void SbiRuntime::implHandleSbxFlags( SbxVariable* pVar, SbxDataType t, sal_uInt32 nOp2 ) 4512 { 4513 bool bWithEvents = ((t & 0xff) == SbxOBJECT && (nOp2 & SBX_TYPE_WITH_EVENTS_FLAG) != 0); 4514 if( bWithEvents ) 4515 { 4516 pVar->SetFlag( SbxFlagBits::WithEvents ); 4517 } 4518 bool bDimAsNew = ((nOp2 & SBX_TYPE_DIM_AS_NEW_FLAG) != 0); 4519 if( bDimAsNew ) 4520 { 4521 pVar->SetFlag( SbxFlagBits::DimAsNew ); 4522 } 4523 bool bFixedString = ((t & 0xff) == SbxSTRING && (nOp2 & SBX_FIXED_LEN_STRING_FLAG) != 0); 4524 if( bFixedString ) 4525 { 4526 sal_uInt16 nCount = static_cast<sal_uInt16>( nOp2 >> 17 ); // len = all bits above 0x10000 4527 OUStringBuffer aBuf; 4528 comphelper::string::padToLength(aBuf, nCount); 4529 pVar->PutString(aBuf.makeStringAndClear()); 4530 } 4531 4532 bool bVarToDim = ((nOp2 & SBX_TYPE_VAR_TO_DIM_FLAG) != 0); 4533 if( bVarToDim ) 4534 { 4535 pVar->SetFlag( SbxFlagBits::VarToDim ); 4536 } 4537 } 4538 4539 // establishing a local variable (+StringID+type) 4540 4541 void SbiRuntime::StepLOCAL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4542 { 4543 if( !refLocals.is() ) 4544 { 4545 refLocals = new SbxArray; 4546 } 4547 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4548 if( refLocals->Find( aName, SbxClassType::DontCare ) == nullptr ) 4549 { 4550 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4551 SbxVariable* p = new SbxVariable( t ); 4552 p->SetName( aName ); 4553 implHandleSbxFlags( p, t, nOp2 ); 4554 refLocals->Put(p, refLocals->Count()); 4555 } 4556 } 4557 4558 // establishing a module-global variable (+StringID+type) 4559 4560 void SbiRuntime::StepPUBLIC_Impl( sal_uInt32 nOp1, sal_uInt32 nOp2, bool bUsedForClassModule ) 4561 { 4562 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4563 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4564 bool bFlag = pMod->IsSet( SbxFlagBits::NoModify ); 4565 pMod->SetFlag( SbxFlagBits::NoModify ); 4566 SbxVariableRef p = pMod->Find( aName, SbxClassType::Property ); 4567 if( p.is() ) 4568 { 4569 pMod->Remove (p.get()); 4570 } 4571 SbProperty* pProp = pMod->GetProperty( aName, t ); 4572 if( !bUsedForClassModule ) 4573 { 4574 pProp->SetFlag( SbxFlagBits::Private ); 4575 } 4576 if( !bFlag ) 4577 { 4578 pMod->ResetFlag( SbxFlagBits::NoModify ); 4579 } 4580 if( pProp ) 4581 { 4582 pProp->SetFlag( SbxFlagBits::DontStore ); 4583 // from 2.7.1996: HACK because of 'reference can't be saved' 4584 pProp->SetFlag( SbxFlagBits::NoModify); 4585 4586 implHandleSbxFlags( pProp, t, nOp2 ); 4587 } 4588 } 4589 4590 void SbiRuntime::StepPUBLIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4591 { 4592 StepPUBLIC_Impl( nOp1, nOp2, false ); 4593 } 4594 4595 void SbiRuntime::StepPUBLIC_P( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4596 { 4597 // Creates module variable that isn't reinitialised when 4598 // between invocations ( for VBASupport & document basic only ) 4599 if( pMod->pImage->bFirstInit ) 4600 { 4601 bool bUsedForClassModule = pImg->IsFlag( SbiImageFlags::CLASSMODULE ); 4602 StepPUBLIC_Impl( nOp1, nOp2, bUsedForClassModule ); 4603 } 4604 } 4605 4606 // establishing a global variable (+StringID+type) 4607 4608 void SbiRuntime::StepGLOBAL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4609 { 4610 if( pImg->IsFlag( SbiImageFlags::CLASSMODULE ) ) 4611 { 4612 StepPUBLIC_Impl( nOp1, nOp2, true ); 4613 } 4614 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4615 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4616 4617 // Store module scope variables at module scope 4618 // in non vba mode these are stored at the library level :/ 4619 // not sure if this really should not be enabled for ALL basic 4620 SbxObject* pStorage = &rBasic; 4621 if ( SbiRuntime::isVBAEnabled() ) 4622 { 4623 pStorage = pMod; 4624 pMod->AddVarName( aName ); 4625 } 4626 4627 bool bFlag = pStorage->IsSet( SbxFlagBits::NoModify ); 4628 rBasic.SetFlag( SbxFlagBits::NoModify ); 4629 SbxVariableRef p = pStorage->Find( aName, SbxClassType::Property ); 4630 if( p.is() ) 4631 { 4632 pStorage->Remove (p.get()); 4633 } 4634 p = pStorage->Make( aName, SbxClassType::Property, t ); 4635 if( !bFlag ) 4636 { 4637 pStorage->ResetFlag( SbxFlagBits::NoModify ); 4638 } 4639 if( p.is() ) 4640 { 4641 p->SetFlag( SbxFlagBits::DontStore ); 4642 // from 2.7.1996: HACK because of 'reference can't be saved' 4643 p->SetFlag( SbxFlagBits::NoModify); 4644 } 4645 } 4646 4647 4648 // Creates global variable that isn't reinitialised when 4649 // basic is restarted, P=PERSIST (+StringID+Typ) 4650 4651 void SbiRuntime::StepGLOBAL_P( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4652 { 4653 if( pMod->pImage->bFirstInit ) 4654 { 4655 StepGLOBAL( nOp1, nOp2 ); 4656 } 4657 } 4658 4659 4660 // Searches for global variable, behavior depends on the fact 4661 // if the variable is initialised for the first time 4662 4663 void SbiRuntime::StepFIND_G( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4664 { 4665 if( pMod->pImage->bFirstInit ) 4666 { 4667 // Behave like always during first init 4668 StepFIND( nOp1, nOp2 ); 4669 } 4670 else 4671 { 4672 // Return dummy variable 4673 SbxDataType t = static_cast<SbxDataType>(nOp2); 4674 OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); 4675 4676 SbxVariable* pDummyVar = new SbxVariable( t ); 4677 pDummyVar->SetName( aName ); 4678 PushVar( pDummyVar ); 4679 } 4680 } 4681 4682 4683 SbxVariable* SbiRuntime::StepSTATIC_Impl( 4684 OUString const & aName, SbxDataType t, sal_uInt32 nOp2 ) 4685 { 4686 SbxVariable* p = nullptr; 4687 if ( pMeth ) 4688 { 4689 SbxArray* pStatics = pMeth->GetStatics(); 4690 if( pStatics && ( pStatics->Find( aName, SbxClassType::DontCare ) == nullptr ) ) 4691 { 4692 p = new SbxVariable( t ); 4693 if( t != SbxVARIANT ) 4694 { 4695 p->SetFlag( SbxFlagBits::Fixed ); 4696 } 4697 p->SetName( aName ); 4698 implHandleSbxFlags( p, t, nOp2 ); 4699 pStatics->Put(p, pStatics->Count()); 4700 } 4701 } 4702 return p; 4703 } 4704 // establishing a static variable (+StringID+type) 4705 void SbiRuntime::StepSTATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4706 { 4707 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4708 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4709 StepSTATIC_Impl( aName, t, nOp2 ); 4710 } 4711 4712 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 4713
