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