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 <sb.hxx> 21 #include <rtl/ustrbuf.hxx> 22 #include <tools/stream.hxx> 23 #include <tools/debug.hxx> 24 #include <vcl/errinf.hxx> 25 #include <comphelper/solarmutex.hxx> 26 #include <basic/sbx.hxx> 27 #include <vcl/svapp.hxx> 28 #include <comphelper/processfactory.hxx> 29 #include <image.hxx> 30 #include <sbunoobj.hxx> 31 #include <sbjsmeth.hxx> 32 #include <sbjsmod.hxx> 33 #include <sbintern.hxx> 34 #include <runtime.hxx> 35 #include <basic/sberrors.hxx> 36 #include <basic/sbuno.hxx> 37 #include <sbprop.hxx> 38 #include <sbobjmod.hxx> 39 #include <stdobj.hxx> 40 #include <basic.hrc> 41 #include <cppuhelper/implbase.hxx> 42 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 43 #include <com/sun/star/util/XCloseBroadcaster.hpp> 44 #include <com/sun/star/util/XCloseListener.hpp> 45 #include <sal/log.hxx> 46 #include <errobject.hxx> 47 #include <memory> 48 #include <unordered_map> 49 50 #include <com/sun/star/script/ModuleType.hpp> 51 #include <com/sun/star/script/ModuleInfo.hpp> 52 53 using namespace ::com::sun::star::script; 54 55 constexpr OUStringLiteral SB_RTLNAME = u"@SBRTL"; 56 // i#i68894# 57 using namespace ::com::sun::star; 58 using namespace ::com::sun::star::uno; 59 using com::sun::star::uno::Reference; 60 using com::sun::star::uno::Any; 61 using com::sun::star::uno::UNO_QUERY; 62 using com::sun::star::lang::XMultiServiceFactory; 63 64 65 class DocBasicItem : public ::cppu::WeakImplHelper< util::XCloseListener > 66 { 67 public: 68 explicit DocBasicItem( StarBASIC& rDocBasic ); 69 virtual ~DocBasicItem() override; 70 71 const SbxObjectRef& getClassModules() const { return mxClassModules; } 72 bool isDocClosed() const { return mbDocClosed; } 73 74 void clearDependingVarsOnDelete( StarBASIC& rDeletedBasic ); 75 76 void startListening(); 77 void stopListening(); 78 79 void setDisposed( bool bDisposed ) 80 { 81 mbDisposed = bDisposed; 82 } 83 84 virtual void SAL_CALL queryClosing( const lang::EventObject& rSource, sal_Bool bGetsOwnership ) override; 85 virtual void SAL_CALL notifyClosing( const lang::EventObject& rSource ) override; 86 virtual void SAL_CALL disposing( const lang::EventObject& rSource ) override; 87 88 private: 89 StarBASIC& mrDocBasic; 90 SbxObjectRef mxClassModules; 91 bool mbDocClosed; 92 bool mbDisposed; 93 }; 94 95 96 DocBasicItem::DocBasicItem( StarBASIC& rDocBasic ) : 97 mrDocBasic( rDocBasic ), 98 mxClassModules( new SbxObject( OUString() ) ), 99 mbDocClosed( false ), 100 mbDisposed( false ) 101 { 102 } 103 104 DocBasicItem::~DocBasicItem() 105 { 106 // tdf#90969 HACK: don't use SolarMutexGuard - there is a horrible global 107 // map GaDocBasicItems holding instances, and these get deleted from exit 108 // handlers, when the SolarMutex is already dead 109 comphelper::SolarMutex *pSolarMutex = comphelper::SolarMutex::get(); 110 if ( pSolarMutex ) 111 pSolarMutex->acquire(); 112 113 try 114 { 115 stopListening(); 116 mxClassModules.clear(); // release with SolarMutex locked 117 } 118 catch (...) 119 { 120 assert(false); 121 } 122 123 pSolarMutex = comphelper::SolarMutex::get(); 124 if ( pSolarMutex ) 125 pSolarMutex->release(); 126 } 127 128 void DocBasicItem::clearDependingVarsOnDelete( StarBASIC& rDeletedBasic ) 129 { 130 mrDocBasic.implClearDependingVarsOnDelete( &rDeletedBasic ); 131 } 132 133 void DocBasicItem::startListening() 134 { 135 Any aThisComp; 136 mrDocBasic.GetUNOConstant( "ThisComponent", aThisComp ); 137 Reference< util::XCloseBroadcaster > xCloseBC( aThisComp, UNO_QUERY ); 138 mbDisposed = !xCloseBC.is(); 139 if( xCloseBC.is() ) 140 { 141 try { xCloseBC->addCloseListener( this ); } catch(const uno::Exception& ) {} 142 } 143 } 144 145 void DocBasicItem::stopListening() 146 { 147 if( mbDisposed ) return; 148 mbDisposed = true; 149 Any aThisComp; 150 if (!mrDocBasic.GetUNOConstant("ThisComponent", aThisComp)) 151 return; 152 153 Reference< util::XCloseBroadcaster > xCloseBC( aThisComp, UNO_QUERY ); 154 if( xCloseBC.is() ) 155 { 156 try { xCloseBC->removeCloseListener( this ); } catch(const uno::Exception& ) {} 157 } 158 } 159 160 void SAL_CALL DocBasicItem::queryClosing( const lang::EventObject& /*rSource*/, sal_Bool /*bGetsOwnership*/ ) 161 { 162 } 163 164 void SAL_CALL DocBasicItem::notifyClosing( const lang::EventObject& /*rEvent*/ ) 165 { 166 stopListening(); 167 mbDocClosed = true; 168 } 169 170 void SAL_CALL DocBasicItem::disposing( const lang::EventObject& /*rEvent*/ ) 171 { 172 stopListening(); 173 } 174 175 176 namespace { 177 178 typedef ::rtl::Reference< DocBasicItem > DocBasicItemRef; 179 180 std::unordered_map< const StarBASIC *, DocBasicItemRef > gaDocBasicItems; 181 182 const DocBasicItem* lclFindDocBasicItem( const StarBASIC* pDocBasic ) 183 { 184 auto it = gaDocBasicItems.find( pDocBasic ); 185 auto end = gaDocBasicItems.end(); 186 return (it != end) ? it->second.get() : nullptr; 187 } 188 189 void lclInsertDocBasicItem( StarBASIC& rDocBasic ) 190 { 191 DocBasicItemRef& rxDocBasicItem = gaDocBasicItems[ &rDocBasic ]; 192 rxDocBasicItem.set( new DocBasicItem( rDocBasic ) ); 193 rxDocBasicItem->startListening(); 194 } 195 196 void lclRemoveDocBasicItem( StarBASIC& rDocBasic ) 197 { 198 auto it = gaDocBasicItems.find( &rDocBasic ); 199 if( it != gaDocBasicItems.end() ) 200 { 201 it->second->stopListening(); 202 gaDocBasicItems.erase( it ); 203 } 204 for( auto& rEntry : gaDocBasicItems ) 205 { 206 rEntry.second->clearDependingVarsOnDelete( rDocBasic ); 207 } 208 } 209 210 StarBASIC* lclGetDocBasicForModule( SbModule* pModule ) 211 { 212 StarBASIC* pRetBasic = nullptr; 213 SbxObject* pCurParent = pModule; 214 while( pCurParent->GetParent() != nullptr ) 215 { 216 pCurParent = pCurParent->GetParent(); 217 StarBASIC* pDocBasic = dynamic_cast<StarBASIC*>( pCurParent ); 218 if( pDocBasic != nullptr && pDocBasic->IsDocBasic() ) 219 { 220 pRetBasic = pDocBasic; 221 break; 222 } 223 } 224 return pRetBasic; 225 } 226 227 } // namespace 228 229 230 SbxObject* StarBASIC::getVBAGlobals( ) 231 { 232 if ( !pVBAGlobals.is() ) 233 { 234 Any aThisDoc; 235 if ( GetUNOConstant("ThisComponent", aThisDoc) ) 236 { 237 Reference< XMultiServiceFactory > xDocFac( aThisDoc, UNO_QUERY ); 238 if ( xDocFac.is() ) 239 { 240 try 241 { 242 xDocFac->createInstance("ooo.vba.VBAGlobals"); 243 } 244 catch(const Exception& ) 245 { 246 // Ignore 247 } 248 } 249 } 250 pVBAGlobals = static_cast<SbUnoObject*>(Find( "VBAGlobals" , SbxClassType::DontCare )); 251 } 252 return pVBAGlobals.get(); 253 } 254 255 // i#i68894# 256 SbxVariable* StarBASIC::VBAFind( const OUString& rName, SbxClassType t ) 257 { 258 if( rName == "ThisComponent" ) 259 { 260 return nullptr; 261 } 262 // rename to init globals 263 if ( getVBAGlobals( ) ) 264 { 265 return pVBAGlobals->Find( rName, t ); 266 } 267 return nullptr; 268 } 269 270 namespace { 271 272 // Create array for conversion SFX <-> VB error code 273 struct SFX_VB_ErrorItem 274 { 275 sal_uInt16 nErrorVB; 276 ErrCode nErrorSFX; 277 }; 278 279 } 280 281 const SFX_VB_ErrorItem SFX_VB_ErrorTab[] = 282 { 283 { 1, ERRCODE_BASIC_EXCEPTION }, // #87844 Map exception to error code 1 284 { 2, ERRCODE_BASIC_SYNTAX }, 285 { 3, ERRCODE_BASIC_NO_GOSUB }, 286 { 4, ERRCODE_BASIC_REDO_FROM_START }, 287 { 5, ERRCODE_BASIC_BAD_ARGUMENT }, 288 { 6, ERRCODE_BASIC_MATH_OVERFLOW }, 289 { 7, ERRCODE_BASIC_NO_MEMORY }, 290 { 8, ERRCODE_BASIC_ALREADY_DIM }, 291 { 9, ERRCODE_BASIC_OUT_OF_RANGE }, 292 { 10, ERRCODE_BASIC_DUPLICATE_DEF }, 293 { 11, ERRCODE_BASIC_ZERODIV }, 294 { 12, ERRCODE_BASIC_VAR_UNDEFINED }, 295 { 13, ERRCODE_BASIC_CONVERSION }, 296 { 14, ERRCODE_BASIC_BAD_PARAMETER }, 297 { 18, ERRCODE_BASIC_USER_ABORT }, 298 { 20, ERRCODE_BASIC_BAD_RESUME }, 299 { 28, ERRCODE_BASIC_STACK_OVERFLOW }, 300 { 35, ERRCODE_BASIC_PROC_UNDEFINED }, 301 { 48, ERRCODE_BASIC_BAD_DLL_LOAD }, 302 { 49, ERRCODE_BASIC_BAD_DLL_CALL }, 303 { 51, ERRCODE_BASIC_INTERNAL_ERROR }, 304 { 52, ERRCODE_BASIC_BAD_CHANNEL }, 305 { 53, ERRCODE_BASIC_FILE_NOT_FOUND }, 306 { 54, ERRCODE_BASIC_BAD_FILE_MODE }, 307 { 55, ERRCODE_BASIC_FILE_ALREADY_OPEN }, 308 { 57, ERRCODE_BASIC_IO_ERROR }, 309 { 58, ERRCODE_BASIC_FILE_EXISTS }, 310 { 59, ERRCODE_BASIC_BAD_RECORD_LENGTH }, 311 { 61, ERRCODE_BASIC_DISK_FULL }, 312 { 62, ERRCODE_BASIC_READ_PAST_EOF }, 313 { 63, ERRCODE_BASIC_BAD_RECORD_NUMBER }, 314 { 67, ERRCODE_BASIC_TOO_MANY_FILES }, 315 { 68, ERRCODE_BASIC_NO_DEVICE }, 316 { 70, ERRCODE_BASIC_ACCESS_DENIED }, 317 { 71, ERRCODE_BASIC_NOT_READY }, 318 { 73, ERRCODE_BASIC_NOT_IMPLEMENTED }, 319 { 74, ERRCODE_BASIC_DIFFERENT_DRIVE }, 320 { 75, ERRCODE_BASIC_ACCESS_ERROR }, 321 { 76, ERRCODE_BASIC_PATH_NOT_FOUND }, 322 { 91, ERRCODE_BASIC_NO_OBJECT }, 323 { 93, ERRCODE_BASIC_BAD_PATTERN }, 324 { 94, ERRCODE_BASIC_IS_NULL }, 325 { 250, ERRCODE_BASIC_DDE_ERROR }, 326 { 280, ERRCODE_BASIC_DDE_WAITINGACK }, 327 { 281, ERRCODE_BASIC_DDE_OUTOFCHANNELS }, 328 { 282, ERRCODE_BASIC_DDE_NO_RESPONSE }, 329 { 283, ERRCODE_BASIC_DDE_MULT_RESPONSES }, 330 { 284, ERRCODE_BASIC_DDE_CHANNEL_LOCKED }, 331 { 285, ERRCODE_BASIC_DDE_NOTPROCESSED }, 332 { 286, ERRCODE_BASIC_DDE_TIMEOUT }, 333 { 287, ERRCODE_BASIC_DDE_USER_INTERRUPT }, 334 { 288, ERRCODE_BASIC_DDE_BUSY }, 335 { 289, ERRCODE_BASIC_DDE_NO_DATA }, 336 { 290, ERRCODE_BASIC_DDE_WRONG_DATA_FORMAT }, 337 { 291, ERRCODE_BASIC_DDE_PARTNER_QUIT }, 338 { 292, ERRCODE_BASIC_DDE_CONV_CLOSED }, 339 { 293, ERRCODE_BASIC_DDE_NO_CHANNEL }, 340 { 294, ERRCODE_BASIC_DDE_INVALID_LINK }, 341 { 295, ERRCODE_BASIC_DDE_QUEUE_OVERFLOW }, 342 { 296, ERRCODE_BASIC_DDE_LINK_ALREADY_EST }, 343 { 297, ERRCODE_BASIC_DDE_LINK_INV_TOPIC }, 344 { 298, ERRCODE_BASIC_DDE_DLL_NOT_FOUND }, 345 { 323, ERRCODE_BASIC_CANNOT_LOAD }, 346 { 341, ERRCODE_BASIC_BAD_INDEX }, 347 { 366, ERRCODE_BASIC_NO_ACTIVE_OBJECT }, 348 { 380, ERRCODE_BASIC_BAD_PROP_VALUE }, 349 { 382, ERRCODE_BASIC_PROP_READONLY }, 350 { 394, ERRCODE_BASIC_PROP_WRITEONLY }, 351 { 420, ERRCODE_BASIC_INVALID_OBJECT }, 352 { 423, ERRCODE_BASIC_NO_METHOD }, 353 { 424, ERRCODE_BASIC_NEEDS_OBJECT }, 354 { 425, ERRCODE_BASIC_INVALID_USAGE_OBJECT }, 355 { 430, ERRCODE_BASIC_NO_OLE }, 356 { 438, ERRCODE_BASIC_BAD_METHOD }, 357 { 440, ERRCODE_BASIC_OLE_ERROR }, 358 { 445, ERRCODE_BASIC_BAD_ACTION }, 359 { 446, ERRCODE_BASIC_NO_NAMED_ARGS }, 360 { 447, ERRCODE_BASIC_BAD_LOCALE }, 361 { 448, ERRCODE_BASIC_NAMED_NOT_FOUND }, 362 { 449, ERRCODE_BASIC_NOT_OPTIONAL }, 363 { 450, ERRCODE_BASIC_WRONG_ARGS }, 364 { 451, ERRCODE_BASIC_NOT_A_COLL }, 365 { 452, ERRCODE_BASIC_BAD_ORDINAL }, 366 { 453, ERRCODE_BASIC_DLLPROC_NOT_FOUND }, 367 { 460, ERRCODE_BASIC_BAD_CLIPBD_FORMAT }, 368 { 951, ERRCODE_BASIC_UNEXPECTED }, 369 { 952, ERRCODE_BASIC_EXPECTED }, 370 { 953, ERRCODE_BASIC_SYMBOL_EXPECTED }, 371 { 954, ERRCODE_BASIC_VAR_EXPECTED }, 372 { 955, ERRCODE_BASIC_LABEL_EXPECTED }, 373 { 956, ERRCODE_BASIC_LVALUE_EXPECTED }, 374 { 957, ERRCODE_BASIC_VAR_DEFINED }, 375 { 958, ERRCODE_BASIC_PROC_DEFINED }, 376 { 959, ERRCODE_BASIC_LABEL_DEFINED }, 377 { 960, ERRCODE_BASIC_UNDEF_VAR }, 378 { 961, ERRCODE_BASIC_UNDEF_ARRAY }, 379 { 962, ERRCODE_BASIC_UNDEF_PROC }, 380 { 963, ERRCODE_BASIC_UNDEF_LABEL }, 381 { 964, ERRCODE_BASIC_UNDEF_TYPE }, 382 { 965, ERRCODE_BASIC_BAD_EXIT }, 383 { 966, ERRCODE_BASIC_BAD_BLOCK }, 384 { 967, ERRCODE_BASIC_BAD_BRACKETS }, 385 { 968, ERRCODE_BASIC_BAD_DECLARATION }, 386 { 969, ERRCODE_BASIC_BAD_PARAMETERS }, 387 { 970, ERRCODE_BASIC_BAD_CHAR_IN_NUMBER }, 388 { 971, ERRCODE_BASIC_MUST_HAVE_DIMS }, 389 { 972, ERRCODE_BASIC_NO_IF }, 390 { 973, ERRCODE_BASIC_NOT_IN_SUBR }, 391 { 974, ERRCODE_BASIC_NOT_IN_MAIN }, 392 { 975, ERRCODE_BASIC_WRONG_DIMS }, 393 { 976, ERRCODE_BASIC_BAD_OPTION }, 394 { 977, ERRCODE_BASIC_CONSTANT_REDECLARED }, 395 { 978, ERRCODE_BASIC_PROG_TOO_LARGE }, 396 { 979, ERRCODE_BASIC_NO_STRINGS_ARRAYS }, 397 { 1000, ERRCODE_BASIC_PROPERTY_NOT_FOUND }, 398 { 1001, ERRCODE_BASIC_METHOD_NOT_FOUND }, 399 { 1002, ERRCODE_BASIC_ARG_MISSING }, 400 { 1003, ERRCODE_BASIC_BAD_NUMBER_OF_ARGS }, 401 { 1004, ERRCODE_BASIC_METHOD_FAILED }, 402 { 1005, ERRCODE_BASIC_SETPROP_FAILED }, 403 { 1006, ERRCODE_BASIC_GETPROP_FAILED }, 404 { 1007, ERRCODE_BASIC_COMPAT }, 405 { 0xFFFF, ErrCode(0xFFFFFFFFUL) } // End mark 406 }; 407 408 // The StarBASIC factory is a hack. When a SbModule is created, its pointer 409 // is saved and given to the following SbProperties/SbMethods. This restores 410 // the Module-relationship. But it works only when a module is loaded. 411 // Can cause troubles with separately loaded properties! 412 413 SbxBaseRef SbiFactory::Create( sal_uInt16 nSbxId, sal_uInt32 nCreator ) 414 { 415 if( nCreator == SBXCR_SBX ) 416 { 417 switch( nSbxId ) 418 { 419 case SBXID_BASIC: 420 return new StarBASIC( nullptr ); 421 case SBXID_BASICMOD: 422 return new SbModule( "" ); 423 case SBXID_BASICPROP: 424 return new SbProperty( "", SbxVARIANT, nullptr ); 425 case SBXID_BASICMETHOD: 426 return new SbMethod( "", SbxVARIANT, nullptr ); 427 case SBXID_JSCRIPTMOD: 428 return new SbJScriptModule; 429 case SBXID_JSCRIPTMETH: 430 return new SbJScriptMethod( SbxVARIANT ); 431 } 432 } 433 return nullptr; 434 } 435 436 SbxObjectRef SbiFactory::CreateObject( const OUString& rClass ) 437 { 438 if( rClass.equalsIgnoreAsciiCase( "StarBASIC" ) ) 439 { 440 return new StarBASIC( nullptr ); 441 } 442 else if( rClass.equalsIgnoreAsciiCase( "StarBASICModule" ) ) 443 { 444 return new SbModule( OUString() ); 445 } 446 else if( rClass.equalsIgnoreAsciiCase( "Collection" ) ) 447 { 448 return new BasicCollection( "Collection" ); 449 } 450 else if( rClass.equalsIgnoreAsciiCase( "FileSystemObject" ) ) 451 { 452 try 453 { 454 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW ); 455 OUString aServiceName("ooo.vba.FileSystemObject"); 456 Reference< XInterface > xInterface( xFactory->createInstance( aServiceName ), UNO_SET_THROW ); 457 return new SbUnoObject( aServiceName, uno::Any( xInterface ) ); 458 } 459 catch(const Exception& ) 460 { 461 } 462 } 463 return nullptr; 464 } 465 466 467 SbxBaseRef SbOLEFactory::Create( sal_uInt16, sal_uInt32 ) 468 { 469 // Not supported 470 return nullptr; 471 } 472 473 SbxObjectRef SbOLEFactory::CreateObject( const OUString& rClassName ) 474 { 475 SbxObjectRef pRet = createOLEObject_Impl( rClassName ); 476 return pRet; 477 } 478 479 480 // SbFormFactory, show user forms by: dim as new <user form name> 481 482 SbxBaseRef SbFormFactory::Create( sal_uInt16, sal_uInt32 ) 483 { 484 // Not supported 485 return nullptr; 486 } 487 488 SbxObjectRef SbFormFactory::CreateObject( const OUString& rClassName ) 489 { 490 if( SbModule* pMod = GetSbData()->pMod ) 491 { 492 if( SbxVariable* pVar = pMod->Find( rClassName, SbxClassType::Object ) ) 493 { 494 if( SbUserFormModule* pFormModule = dynamic_cast<SbUserFormModule*>( pVar->GetObject() ) ) 495 { 496 bool bInitState = pFormModule->getInitState(); 497 if( bInitState ) 498 { 499 // Not the first instantiate, reset 500 pFormModule->ResetApiObj( false/*bTriggerTerminateEvent*/ ); 501 pFormModule->setInitState( false ); 502 } 503 else 504 { 505 pFormModule->Load(); 506 } 507 return pFormModule->CreateInstance(); 508 } 509 } 510 } 511 return nullptr; 512 } 513 514 515 // SbTypeFactory 516 517 SbxObjectRef cloneTypeObjectImpl( const SbxObject& rTypeObj ) 518 { 519 SbxObjectRef pRet = new SbxObject( rTypeObj ); 520 pRet->PutObject( pRet.get() ); 521 522 // Copy the properties, not only the reference to them 523 SbxArray* pProps = pRet->GetProperties(); 524 sal_uInt32 nCount = pProps->Count(); 525 for( sal_uInt32 i = 0 ; i < nCount ; i++ ) 526 { 527 SbxVariable* pVar = pProps->Get(i); 528 SbxProperty* pProp = dynamic_cast<SbxProperty*>( pVar ); 529 if( pProp ) 530 { 531 SbxProperty* pNewProp = new SbxProperty( *pProp ); 532 SbxDataType eVarType = pVar->GetType(); 533 if( eVarType & SbxARRAY ) 534 { 535 SbxBase* pParObj = pVar->GetObject(); 536 SbxDimArray* pSource = dynamic_cast<SbxDimArray*>( pParObj ); 537 SbxDimArray* pDest = new SbxDimArray( pVar->GetType() ); 538 539 pDest->setHasFixedSize( pSource && pSource->hasFixedSize() ); 540 if (pSource && pSource->GetDims() && pSource->hasFixedSize()) 541 { 542 sal_Int32 lb = 0; 543 sal_Int32 ub = 0; 544 for (sal_Int32 j = 1; j <= pSource->GetDims(); ++j) 545 { 546 pSource->GetDim(j, lb, ub); 547 pDest->AddDim(lb, ub); 548 } 549 } 550 else 551 { 552 pDest->unoAddDim(0, -1); // variant array 553 } 554 SbxFlagBits nSavFlags = pVar->GetFlags(); 555 pNewProp->ResetFlag( SbxFlagBits::Fixed ); 556 // need to reset the FIXED flag 557 // when calling PutObject ( because the type will not match Object ) 558 pNewProp->PutObject( pDest ); 559 pNewProp->SetFlags( nSavFlags ); 560 } 561 if( eVarType == SbxOBJECT ) 562 { 563 SbxBase* pObjBase = pVar->GetObject(); 564 SbxObject* pSrcObj = dynamic_cast<SbxObject*>( pObjBase ); 565 SbxObjectRef pDestObj; 566 if( pSrcObj != nullptr ) 567 pDestObj = cloneTypeObjectImpl( *pSrcObj ); 568 pNewProp->PutObject( pDestObj.get() ); 569 } 570 pProps->PutDirect( pNewProp, i ); 571 } 572 } 573 return pRet; 574 } 575 576 SbxBaseRef SbTypeFactory::Create( sal_uInt16, sal_uInt32 ) 577 { 578 // Not supported 579 return nullptr; 580 } 581 582 SbxObjectRef SbTypeFactory::CreateObject( const OUString& rClassName ) 583 { 584 SbxObjectRef pRet; 585 SbModule* pMod = GetSbData()->pMod; 586 if( pMod ) 587 { 588 const SbxObject* pObj = pMod->FindType( rClassName ); 589 if( pObj ) 590 { 591 pRet = cloneTypeObjectImpl( *pObj ); 592 } 593 } 594 return pRet; 595 } 596 597 SbxObjectRef createUserTypeImpl( const OUString& rClassName ) 598 { 599 SbxObjectRef pRetObj = GetSbData()->pTypeFac->CreateObject( rClassName ); 600 return pRetObj; 601 } 602 603 604 SbClassModuleObject::SbClassModuleObject( SbModule* pClassModule ) 605 : SbModule( pClassModule->GetName() ) 606 , mpClassModule( pClassModule ) 607 , mbInitializeEventDone( false ) 608 { 609 aOUSource = pClassModule->aOUSource; 610 aComment = pClassModule->aComment; 611 // see comment in destructor about these two 612 pImage.reset(pClassModule->pImage.get()); 613 pBreaks = pClassModule->pBreaks; 614 615 SetClassName( pClassModule->GetName() ); 616 617 // Allow search only internally 618 ResetFlag( SbxFlagBits::GlobalSearch ); 619 620 // Copy the methods from original class module 621 SbxArray* pClassMethods = pClassModule->GetMethods().get(); 622 sal_uInt32 nMethodCount = pClassMethods->Count(); 623 sal_uInt32 i; 624 for( i = 0 ; i < nMethodCount ; i++ ) 625 { 626 SbxVariable* pVar = pClassMethods->Get(i); 627 628 // Exclude SbIfaceMapperMethod to copy them in a second step 629 SbIfaceMapperMethod* pIfaceMethod = dynamic_cast<SbIfaceMapperMethod*>( pVar ); 630 if( !pIfaceMethod ) 631 { 632 SbMethod* pMethod = dynamic_cast<SbMethod*>( pVar ); 633 if( pMethod ) 634 { 635 SbxFlagBits nFlags_ = pMethod->GetFlags(); 636 pMethod->SetFlag( SbxFlagBits::NoBroadcast ); 637 SbMethod* pNewMethod = new SbMethod( *pMethod ); 638 pNewMethod->ResetFlag( SbxFlagBits::NoBroadcast ); 639 pMethod->SetFlags( nFlags_ ); 640 pNewMethod->pMod = this; 641 pNewMethod->SetParent( this ); 642 pMethods->PutDirect( pNewMethod, i ); 643 StartListening(pNewMethod->GetBroadcaster(), DuplicateHandling::Prevent); 644 } 645 } 646 } 647 648 // Copy SbIfaceMapperMethod in a second step to ensure that 649 // the corresponding base methods have already been copied 650 for( i = 0 ; i < nMethodCount ; i++ ) 651 { 652 SbxVariable* pVar = pClassMethods->Get(i); 653 654 SbIfaceMapperMethod* pIfaceMethod = dynamic_cast<SbIfaceMapperMethod*>( pVar ); 655 if( pIfaceMethod ) 656 { 657 SbMethod* pImplMethod = pIfaceMethod->getImplMethod(); 658 if( !pImplMethod ) 659 { 660 OSL_FAIL( "No ImplMethod" ); 661 continue; 662 } 663 664 // Search for own copy of ImplMethod 665 SbxVariable* p = pMethods->Find( pImplMethod->GetName(), SbxClassType::Method ); 666 SbMethod* pImplMethodCopy = dynamic_cast<SbMethod*>( p ); 667 if( !pImplMethodCopy ) 668 { 669 OSL_FAIL( "Found no ImplMethod copy" ); 670 continue; 671 } 672 SbIfaceMapperMethod* pNewIfaceMethod = 673 new SbIfaceMapperMethod( pIfaceMethod->GetName(), pImplMethodCopy ); 674 pMethods->PutDirect( pNewIfaceMethod, i ); 675 } 676 } 677 678 // Copy the properties from original class module 679 SbxArray* pClassProps = pClassModule->GetProperties(); 680 sal_uInt32 nPropertyCount = pClassProps->Count(); 681 for( i = 0 ; i < nPropertyCount ; i++ ) 682 { 683 SbxVariable* pVar = pClassProps->Get(i); 684 SbProcedureProperty* pProcedureProp = dynamic_cast<SbProcedureProperty*>( pVar ); 685 if( pProcedureProp ) 686 { 687 SbxFlagBits nFlags_ = pProcedureProp->GetFlags(); 688 pProcedureProp->SetFlag( SbxFlagBits::NoBroadcast ); 689 SbProcedureProperty* pNewProp = new SbProcedureProperty 690 ( pProcedureProp->GetName(), pProcedureProp->GetType() ); 691 pNewProp->SetFlags( nFlags_ ); // Copy flags 692 pNewProp->ResetFlag( SbxFlagBits::NoBroadcast ); // except the Broadcast if it was set 693 pProcedureProp->SetFlags( nFlags_ ); 694 pProps->PutDirect( pNewProp, i ); 695 StartListening(pNewProp->GetBroadcaster(), DuplicateHandling::Prevent); 696 } 697 else 698 { 699 SbxProperty* pProp = dynamic_cast<SbxProperty*>( pVar ); 700 if( pProp ) 701 { 702 SbxFlagBits nFlags_ = pProp->GetFlags(); 703 pProp->SetFlag( SbxFlagBits::NoBroadcast ); 704 SbxProperty* pNewProp = new SbxProperty( *pProp ); 705 706 // Special handling for modules instances and collections, they need 707 // to be instantiated, otherwise all refer to the same base object 708 SbxDataType eVarType = pProp->GetType(); 709 if( eVarType == SbxOBJECT ) 710 { 711 SbxBase* pObjBase = pProp->GetObject(); 712 SbxObject* pObj = dynamic_cast<SbxObject*>( pObjBase ); 713 if( pObj != nullptr ) 714 { 715 const OUString& aObjClass = pObj->GetClassName(); 716 717 SbClassModuleObject* pClassModuleObj = dynamic_cast<SbClassModuleObject*>( pObjBase ); 718 if( pClassModuleObj != nullptr ) 719 { 720 SbModule* pLclClassModule = pClassModuleObj->getClassModule(); 721 SbClassModuleObject* pNewObj = new SbClassModuleObject( pLclClassModule ); 722 pNewObj->SetName( pProp->GetName() ); 723 pNewObj->SetParent( pLclClassModule->pParent ); 724 pNewProp->PutObject( pNewObj ); 725 } 726 else if( aObjClass.equalsIgnoreAsciiCase( "Collection" ) ) 727 { 728 BasicCollection* pNewCollection = new BasicCollection( "Collection" ); 729 pNewCollection->SetName( pProp->GetName() ); 730 pNewCollection->SetParent( pClassModule->pParent ); 731 pNewProp->PutObject( pNewCollection ); 732 } 733 } 734 } 735 736 pNewProp->ResetFlag( SbxFlagBits::NoBroadcast ); 737 pNewProp->SetParent( this ); 738 pProps->PutDirect( pNewProp, i ); 739 pProp->SetFlags( nFlags_ ); 740 } 741 } 742 } 743 SetModuleType( ModuleType::CLASS ); 744 mbVBACompat = pClassModule->mbVBACompat; 745 } 746 747 SbClassModuleObject::~SbClassModuleObject() 748 { 749 // do not trigger termination event when document is already closed 750 if( StarBASIC::IsRunning() ) 751 if( StarBASIC* pDocBasic = lclGetDocBasicForModule( this ) ) 752 if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) ) 753 if( !pDocBasicItem->isDocClosed() ) 754 triggerTerminateEvent(); 755 756 // prevent the base class destructor from deleting these because 757 // we do not actually own them 758 pImage.release(); 759 pBreaks = nullptr; 760 } 761 762 void SbClassModuleObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) 763 { 764 handleProcedureProperties( rBC, rHint ); 765 } 766 767 SbxVariable* SbClassModuleObject::Find( const OUString& rName, SbxClassType t ) 768 { 769 SbxVariable* pRes = SbxObject::Find( rName, t ); 770 if( pRes ) 771 { 772 triggerInitializeEvent(); 773 774 SbIfaceMapperMethod* pIfaceMapperMethod = dynamic_cast<SbIfaceMapperMethod*>( pRes ); 775 if( pIfaceMapperMethod ) 776 { 777 pRes = pIfaceMapperMethod->getImplMethod(); 778 pRes->SetFlag( SbxFlagBits::ExtFound ); 779 } 780 } 781 return pRes; 782 } 783 784 void SbClassModuleObject::triggerInitializeEvent() 785 { 786 if( mbInitializeEventDone ) 787 { 788 return; 789 } 790 791 mbInitializeEventDone = true; 792 793 // Search method 794 SbxVariable* pMeth = SbxObject::Find("Class_Initialize", SbxClassType::Method); 795 if( pMeth ) 796 { 797 SbxValues aVals; 798 pMeth->Get( aVals ); 799 } 800 } 801 802 void SbClassModuleObject::triggerTerminateEvent() 803 { 804 if( !mbInitializeEventDone || GetSbData()->bRunInit ) 805 { 806 return; 807 } 808 // Search method 809 SbxVariable* pMeth = SbxObject::Find("Class_Terminate", SbxClassType::Method ); 810 if( pMeth ) 811 { 812 SbxValues aVals; 813 pMeth->Get( aVals ); 814 } 815 } 816 817 818 SbClassData::SbClassData() 819 { 820 mxIfaces = new SbxArray(); 821 } 822 823 void SbClassData::clear() 824 { 825 mxIfaces->Clear(); 826 maRequiredTypes.clear(); 827 } 828 829 SbClassFactory::SbClassFactory() 830 { 831 xClassModules = new SbxObject( OUString() ); 832 } 833 834 SbClassFactory::~SbClassFactory() 835 {} 836 837 void SbClassFactory::AddClassModule( SbModule* pClassModule ) 838 { 839 SbxObjectRef xToUseClassModules = xClassModules; 840 841 if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pClassModule ) ) 842 if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) ) 843 xToUseClassModules = pDocBasicItem->getClassModules(); 844 845 SbxObject* pParent = pClassModule->GetParent(); 846 xToUseClassModules->Insert( pClassModule ); 847 pClassModule->SetParent( pParent ); 848 } 849 850 void SbClassFactory::RemoveClassModule( SbModule* pClassModule ) 851 { 852 xClassModules->Remove( pClassModule ); 853 } 854 855 SbxBaseRef SbClassFactory::Create( sal_uInt16, sal_uInt32 ) 856 { 857 // Not supported 858 return nullptr; 859 } 860 861 SbxObjectRef SbClassFactory::CreateObject( const OUString& rClassName ) 862 { 863 SbxObjectRef xToUseClassModules = xClassModules; 864 865 if( SbModule* pMod = GetSbData()->pMod ) 866 { 867 if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pMod ) ) 868 { 869 if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) ) 870 { 871 xToUseClassModules = pDocBasicItem->getClassModules(); 872 } 873 } 874 } 875 SbxVariable* pVar = xToUseClassModules->Find( rClassName, SbxClassType::Object ); 876 SbxObjectRef pRet; 877 if( pVar ) 878 { 879 SbModule* pVarMod = static_cast<SbModule*>(pVar); 880 pRet = new SbClassModuleObject( pVarMod ); 881 } 882 return pRet; 883 } 884 885 SbModule* SbClassFactory::FindClass( const OUString& rClassName ) 886 { 887 SbxVariable* pVar = xClassModules->Find( rClassName, SbxClassType::DontCare ); 888 SbModule* pMod = pVar ? static_cast<SbModule*>(pVar) : nullptr; 889 return pMod; 890 } 891 892 StarBASIC::StarBASIC( StarBASIC* p, bool bIsDocBasic ) 893 : SbxObject("StarBASIC"), bDocBasic( bIsDocBasic ) 894 { 895 SetParent( p ); 896 bNoRtl = bBreak = false; 897 bVBAEnabled = false; 898 899 if( !GetSbData()->nInst++ ) 900 { 901 GetSbData()->pSbFac.reset( new SbiFactory ); 902 AddFactory( GetSbData()->pSbFac.get() ); 903 GetSbData()->pTypeFac.reset(new SbTypeFactory); 904 AddFactory( GetSbData()->pTypeFac.get() ); 905 GetSbData()->pClassFac.reset(new SbClassFactory); 906 AddFactory( GetSbData()->pClassFac.get() ); 907 GetSbData()->pOLEFac.reset(new SbOLEFactory); 908 AddFactory( GetSbData()->pOLEFac.get() ); 909 GetSbData()->pFormFac.reset(new SbFormFactory); 910 AddFactory( GetSbData()->pFormFac.get() ); 911 GetSbData()->pUnoFac.reset( new SbUnoFactory ); 912 AddFactory( GetSbData()->pUnoFac.get() ); 913 } 914 pRtl = new SbiStdObject(SB_RTLNAME, this ); 915 // Search via StarBasic is always global 916 SetFlag( SbxFlagBits::GlobalSearch ); 917 pVBAGlobals = nullptr; 918 bQuit = false; 919 920 if( bDocBasic ) 921 { 922 lclInsertDocBasicItem( *this ); 923 } 924 } 925 926 // #51727 Override SetModified so that the modified state 927 // is not given to the parent 928 void StarBASIC::SetModified( bool b ) 929 { 930 SbxBase::SetModified( b ); 931 } 932 933 StarBASIC::~StarBASIC() 934 { 935 // Needs to be first action as it can trigger events 936 disposeComVariablesForBasic( this ); 937 938 if( !--GetSbData()->nInst ) 939 { 940 RemoveFactory( GetSbData()->pSbFac.get() ); 941 GetSbData()->pSbFac.reset(); 942 RemoveFactory( GetSbData()->pUnoFac.get() ); 943 GetSbData()->pUnoFac.reset(); 944 RemoveFactory( GetSbData()->pTypeFac.get() ); 945 GetSbData()->pTypeFac.reset(); 946 RemoveFactory( GetSbData()->pClassFac.get() ); 947 GetSbData()->pClassFac.reset(); 948 RemoveFactory( GetSbData()->pOLEFac.get() ); 949 GetSbData()->pOLEFac.reset(); 950 RemoveFactory( GetSbData()->pFormFac.get() ); 951 GetSbData()->pFormFac.reset(); 952 953 if( SbiGlobals::pGlobals ) 954 { 955 delete SbiGlobals::pGlobals; 956 SbiGlobals::pGlobals = nullptr; 957 } 958 } 959 else if( bDocBasic ) 960 { 961 ErrCode eOld = SbxBase::GetError(); 962 963 lclRemoveDocBasicItem( *this ); 964 965 SbxBase::ResetError(); 966 if( eOld != ERRCODE_NONE ) 967 { 968 SbxBase::SetError( eOld ); 969 } 970 } 971 972 // #100326 Set Parent NULL in registered listeners 973 if( xUnoListeners.is() ) 974 { 975 sal_uInt32 uCount = xUnoListeners->Count(); 976 for( sal_uInt32 i = 0 ; i < uCount ; i++ ) 977 { 978 SbxVariable* pListenerObj = xUnoListeners->Get(i); 979 pListenerObj->SetParent( nullptr ); 980 } 981 xUnoListeners = nullptr; 982 } 983 984 clearUnoMethodsForBasic( this ); 985 } 986 987 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC* pDeletedBasic ) 988 { 989 if( this != pDeletedBasic ) 990 { 991 for( const auto& pModule: pModules) 992 { 993 pModule->ClearVarsDependingOnDeletedBasic( pDeletedBasic ); 994 } 995 } 996 997 for (sal_uInt32 nObj = 0; nObj < pObjs->Count(); nObj++) 998 { 999 SbxVariable* pVar = pObjs->Get(nObj); 1000 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( pVar ); 1001 if( pBasic && pBasic != pDeletedBasic ) 1002 { 1003 pBasic->implClearDependingVarsOnDelete( pDeletedBasic ); 1004 } 1005 } 1006 } 1007 1008 1009 SbModule* StarBASIC::MakeModule( const OUString& rName, const OUString& rSrc ) 1010 { 1011 ModuleInfo aInfo; 1012 aInfo.ModuleType = ModuleType::NORMAL; 1013 return MakeModule( rName, aInfo, rSrc ); 1014 } 1015 SbModule* StarBASIC::MakeModule( const OUString& rName, const ModuleInfo& mInfo, const OUString& rSrc ) 1016 { 1017 1018 SAL_INFO( 1019 "basic", 1020 "create module " << rName << " type mInfo " << mInfo.ModuleType); 1021 SbModule* p = nullptr; 1022 switch ( mInfo.ModuleType ) 1023 { 1024 case ModuleType::DOCUMENT: 1025 // In theory we should be able to create Object modules 1026 // in ordinary basic ( in vba mode thought these are create 1027 // by the application/basic and not by the user ) 1028 p = new SbObjModule( rName, mInfo, isVBAEnabled() ); 1029 break; 1030 case ModuleType::CLASS: 1031 p = new SbModule( rName, isVBAEnabled() ); 1032 p->SetModuleType( ModuleType::CLASS ); 1033 break; 1034 case ModuleType::FORM: 1035 p = new SbUserFormModule( rName, mInfo, isVBAEnabled() ); 1036 break; 1037 default: 1038 p = new SbModule( rName, isVBAEnabled() ); 1039 break; 1040 } 1041 p->SetSource32( rSrc ); 1042 p->SetParent( this ); 1043 pModules.emplace_back(p); 1044 SetModified( true ); 1045 return p; 1046 } 1047 1048 void StarBASIC::Insert( SbxVariable* pVar ) 1049 { 1050 if( auto pModule = dynamic_cast<SbModule*>(pVar) ) 1051 { 1052 pModules.emplace_back(pModule); 1053 pVar->SetParent( this ); 1054 StartListening(pVar->GetBroadcaster(), DuplicateHandling::Prevent); 1055 } 1056 else 1057 { 1058 bool bWasModified = IsModified(); 1059 SbxObject::Insert( pVar ); 1060 if( !bWasModified && pVar->IsSet( SbxFlagBits::DontStore ) ) 1061 { 1062 SetModified( false ); 1063 } 1064 } 1065 } 1066 1067 void StarBASIC::Remove( SbxVariable* pVar ) 1068 { 1069 SbModule* pModule = dynamic_cast<SbModule*>(pVar); 1070 if( pModule ) 1071 { 1072 // #87540 Can be last reference! 1073 SbModuleRef xVar = pModule; 1074 pModules.erase(std::remove(pModules.begin(), pModules.end(), xVar)); 1075 pVar->SetParent( nullptr ); 1076 EndListening( pVar->GetBroadcaster() ); 1077 } 1078 else 1079 { 1080 SbxObject::Remove( pVar ); 1081 } 1082 } 1083 1084 void StarBASIC::Clear() 1085 { 1086 pModules.clear(); 1087 } 1088 1089 SbModule* StarBASIC::FindModule( std::u16string_view rName ) 1090 { 1091 for (const auto& pModule: pModules) 1092 { 1093 if( pModule->GetName().equalsIgnoreAsciiCase( rName ) ) 1094 { 1095 return pModule.get(); 1096 } 1097 } 1098 return nullptr; 1099 } 1100 1101 1102 struct ClassModuleRunInitItem 1103 { 1104 SbModule* m_pModule; 1105 bool m_bProcessing; 1106 bool m_bRunInitDone; 1107 1108 ClassModuleRunInitItem() 1109 : m_pModule( nullptr ) 1110 , m_bProcessing( false ) 1111 , m_bRunInitDone( false ) 1112 {} 1113 explicit ClassModuleRunInitItem( SbModule* pModule ) 1114 : m_pModule( pModule ) 1115 , m_bProcessing( false ) 1116 , m_bRunInitDone( false ) 1117 {} 1118 }; 1119 1120 // Derive from unordered_map type instead of typedef 1121 // to allow forward declaration in sbmod.hxx 1122 class ModuleInitDependencyMap : public 1123 std::unordered_map< OUString, ClassModuleRunInitItem > 1124 {}; 1125 1126 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap& rMap, ClassModuleRunInitItem& rItem ) 1127 { 1128 rItem.m_bProcessing = true; 1129 1130 SbModule* pModule = rItem.m_pModule; 1131 if( pModule->pClassData != nullptr ) 1132 { 1133 std::vector< OUString >& rReqTypes = pModule->pClassData->maRequiredTypes; 1134 for( const auto& rStr : rReqTypes ) 1135 { 1136 // Is required type a class module? 1137 ModuleInitDependencyMap::iterator itFind = rMap.find( rStr ); 1138 if( itFind != rMap.end() ) 1139 { 1140 ClassModuleRunInitItem& rParentItem = itFind->second; 1141 if( rParentItem.m_bProcessing ) 1142 { 1143 // TODO: raise error? 1144 OSL_FAIL( "Cyclic module dependency detected" ); 1145 continue; 1146 } 1147 1148 if( !rParentItem.m_bRunInitDone ) 1149 { 1150 implProcessModuleRunInit( rMap, rParentItem ); 1151 } 1152 } 1153 } 1154 } 1155 1156 pModule->RunInit(); 1157 rItem.m_bRunInitDone = true; 1158 rItem.m_bProcessing = false; 1159 } 1160 1161 // Run Init-Code of all modules (including inserted libraries) 1162 void StarBASIC::InitAllModules( StarBASIC const * pBasicNotToInit ) 1163 { 1164 SolarMutexGuard guard; 1165 1166 // Init own modules 1167 for (const auto& pModule: pModules) 1168 { 1169 pModule->Compile(); 1170 } 1171 // compile modules first then RunInit ( otherwise there is 1172 // can be order dependency, e.g. classmodule A has a member 1173 // of type classmodule B and classmodule B hasn't been compiled yet ) 1174 1175 // Consider required types to init in right order. Class modules 1176 // that are required by other modules have to be initialized first. 1177 ModuleInitDependencyMap aMIDMap; 1178 for (const auto& pModule: pModules) 1179 { 1180 OUString aModuleName = pModule->GetName(); 1181 if( pModule->isProxyModule() ) 1182 { 1183 aMIDMap[aModuleName] = ClassModuleRunInitItem( pModule.get() ); 1184 } 1185 } 1186 1187 for (auto & elem : aMIDMap) 1188 { 1189 ClassModuleRunInitItem& rItem = elem.second; 1190 SbModule::implProcessModuleRunInit( aMIDMap, rItem ); 1191 } 1192 1193 // Call RunInit on standard modules 1194 for (const auto& pModule: pModules) 1195 { 1196 if( !pModule->isProxyModule() ) 1197 { 1198 pModule->RunInit(); 1199 } 1200 } 1201 1202 // Check all objects if they are BASIC, 1203 // if yes initialize 1204 for (sal_uInt32 nObj = 0; nObj < pObjs->Count(); nObj++) 1205 { 1206 SbxVariable* pVar = pObjs->Get(nObj); 1207 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( pVar ); 1208 if( pBasic && pBasic != pBasicNotToInit ) 1209 { 1210 pBasic->InitAllModules(); 1211 } 1212 } 1213 } 1214 1215 // #88329 Put modules back to not initialised state to 1216 // force reinitialisation at next start 1217 void StarBASIC::DeInitAllModules() 1218 { 1219 // Deinit own modules 1220 for (const auto& pModule: pModules) 1221 { 1222 if( pModule->pImage && !pModule->isProxyModule() && dynamic_cast<SbObjModule*>( pModule.get()) == nullptr ) 1223 { 1224 pModule->pImage->bInit = false; 1225 } 1226 } 1227 1228 for (sal_uInt32 nObj = 0; nObj < pObjs->Count(); nObj++) 1229 { 1230 SbxVariable* pVar = pObjs->Get(nObj); 1231 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( pVar ); 1232 if( pBasic ) 1233 { 1234 pBasic->DeInitAllModules(); 1235 } 1236 } 1237 } 1238 1239 // This implementation at first searches within the runtime library, 1240 // then it looks for an element within one module. This module can be 1241 // a public var or an entrypoint. If it is not found and we look for a 1242 // method and a module with the given name is found the search continues 1243 // for entrypoint "Main". 1244 // If this fails again a conventional search over objects is performend. 1245 SbxVariable* StarBASIC::Find( const OUString& rName, SbxClassType t ) 1246 { 1247 SbxVariable* pRes = nullptr; 1248 SbModule* pNamed = nullptr; 1249 // "Extended" search in Runtime Lib 1250 // but only if SbiRuntime has not set the flag 1251 if( !bNoRtl ) 1252 { 1253 if( t == SbxClassType::DontCare || t == SbxClassType::Object ) 1254 { 1255 if( rName.equalsIgnoreAsciiCase( SB_RTLNAME ) ) 1256 { 1257 pRes = pRtl.get(); 1258 } 1259 } 1260 if( !pRes ) 1261 { 1262 pRes = static_cast<SbiStdObject*>(pRtl.get())->Find( rName, t ); 1263 } 1264 if( pRes ) 1265 { 1266 pRes->SetFlag( SbxFlagBits::ExtFound ); 1267 } 1268 } 1269 // Search module 1270 if( !pRes ) 1271 { 1272 for (const auto& pModule: pModules) 1273 { 1274 if( pModule->IsVisible() ) 1275 { 1276 // Remember module for Main() call 1277 // or is the name equal?!? 1278 if( pModule->GetName().equalsIgnoreAsciiCase( rName ) ) 1279 { 1280 if( t == SbxClassType::Object || t == SbxClassType::DontCare ) 1281 { 1282 pRes = pModule.get(); break; 1283 } 1284 pNamed = pModule.get(); 1285 } 1286 // Only variables qualified by the Module Name e.g. Sheet1.foo 1287 // should work for Document && Class type Modules 1288 sal_Int32 nType = pModule->GetModuleType(); 1289 if ( nType == ModuleType::DOCUMENT || nType == ModuleType::FORM ) 1290 { 1291 continue; 1292 } 1293 // otherwise check if the element is available 1294 // unset GBLSEARCH-Flag (due to recursion) 1295 SbxFlagBits nGblFlag = pModule->GetFlags() & SbxFlagBits::GlobalSearch; 1296 pModule->ResetFlag( SbxFlagBits::GlobalSearch ); 1297 pRes = pModule->Find( rName, t ); 1298 pModule->SetFlag( nGblFlag ); 1299 if( pRes ) 1300 { 1301 break; 1302 } 1303 } 1304 } 1305 } 1306 OUString aMainStr("Main"); 1307 if( !pRes && pNamed && ( t == SbxClassType::Method || t == SbxClassType::DontCare ) && 1308 !pNamed->GetName().equalsIgnoreAsciiCase( aMainStr ) ) 1309 { 1310 pRes = pNamed->Find( aMainStr, SbxClassType::Method ); 1311 } 1312 if( !pRes ) 1313 { 1314 pRes = SbxObject::Find( rName, t ); 1315 } 1316 return pRes; 1317 } 1318 1319 bool StarBASIC::Call( const OUString& rName, SbxArray* pParam ) 1320 { 1321 bool bRes = SbxObject::Call( rName, pParam ); 1322 if( !bRes ) 1323 { 1324 ErrCode eErr = SbxBase::GetError(); 1325 SbxBase::ResetError(); 1326 if( eErr != ERRCODE_NONE ) 1327 { 1328 RTError( eErr, OUString(), 0, 0, 0 ); 1329 } 1330 } 1331 return bRes; 1332 } 1333 1334 // Find method via name (e.g. query via BASIC IDE) 1335 SbxBase* StarBASIC::FindSBXInCurrentScope( const OUString& rName ) 1336 { 1337 if( !GetSbData()->pInst ) 1338 { 1339 return nullptr; 1340 } 1341 if( !GetSbData()->pInst->pRun ) 1342 { 1343 return nullptr; 1344 } 1345 return GetSbData()->pInst->pRun->FindElementExtern( rName ); 1346 } 1347 1348 void StarBASIC::QuitAndExitApplication() 1349 { 1350 Stop(); 1351 bQuit = true; 1352 } 1353 1354 void StarBASIC::Stop() 1355 { 1356 SbiInstance* p = GetSbData()->pInst; 1357 if( p ) 1358 p->Stop(); 1359 } 1360 1361 bool StarBASIC::IsRunning() 1362 { 1363 return GetSbData()->pInst != nullptr; 1364 } 1365 1366 SbMethod* StarBASIC::GetActiveMethod( sal_uInt16 nLevel ) 1367 { 1368 if( GetSbData()->pInst ) 1369 { 1370 return GetSbData()->pInst->GetCaller( nLevel ); 1371 } 1372 else 1373 { 1374 return nullptr; 1375 } 1376 } 1377 1378 SbModule* StarBASIC::GetActiveModule() 1379 { 1380 if( GetSbData()->pInst && !GetSbData()->bCompilerError ) 1381 { 1382 return GetSbData()->pInst->GetActiveModule(); 1383 } 1384 else 1385 { 1386 return GetSbData()->pCompMod; 1387 } 1388 } 1389 1390 BasicDebugFlags StarBASIC::BreakPoint( sal_Int32 l, sal_Int32 c1, sal_Int32 c2 ) 1391 { 1392 SetErrorData( ERRCODE_NONE, l, c1, c2 ); 1393 bBreak = true; 1394 if( GetSbData()->aBreakHdl.IsSet() ) 1395 { 1396 return GetSbData()->aBreakHdl.Call( this ); 1397 } 1398 else 1399 { 1400 return BreakHdl(); 1401 } 1402 } 1403 1404 BasicDebugFlags StarBASIC::StepPoint( sal_Int32 l, sal_Int32 c1, sal_Int32 c2 ) 1405 { 1406 SetErrorData( ERRCODE_NONE, l, c1, c2 ); 1407 bBreak = false; 1408 if( GetSbData()->aBreakHdl.IsSet() ) 1409 { 1410 return GetSbData()->aBreakHdl.Call( this ); 1411 } 1412 else 1413 { 1414 return BreakHdl(); 1415 } 1416 } 1417 1418 BasicDebugFlags StarBASIC::BreakHdl() 1419 { 1420 return aBreakHdl.IsSet() ? aBreakHdl.Call( this ) : BasicDebugFlags::Continue; 1421 } 1422 1423 // Calls for error handler and break handler 1424 sal_uInt16 StarBASIC::GetLine() { return GetSbData()->nLine; } 1425 sal_uInt16 StarBASIC::GetCol1() { return GetSbData()->nCol1; } 1426 sal_uInt16 StarBASIC::GetCol2() { return GetSbData()->nCol2; } 1427 1428 // Specific to error handler 1429 ErrCode const & StarBASIC::GetErrorCode() { return GetSbData()->nCode; } 1430 const OUString& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg; } 1431 1432 // From 1996-03-29: 1433 // The mapping between the old and the new error codes take place by searching 1434 // through the table SFX_VB_ErrorTab[]. This is indeed not with good performance, 1435 // but it consumes much less memory than corresponding switch blocks. 1436 // Because the conversion of error codes has not to be fast. There is no 1437 // binary search by VB Error -> Error SFX. 1438 1439 // Map back new error codes to old, Sbx-compatible 1440 sal_uInt16 StarBASIC::GetVBErrorCode( ErrCode nError ) 1441 { 1442 sal_uInt16 nRet = 0; 1443 1444 if( SbiRuntime::isVBAEnabled() ) 1445 { 1446 if ( nError == ERRCODE_BASIC_ARRAY_FIX ) 1447 return 10; 1448 else if ( nError == ERRCODE_BASIC_STRING_OVERFLOW ) 1449 return 14; 1450 else if ( nError == ERRCODE_BASIC_EXPR_TOO_COMPLEX ) 1451 return 16; 1452 else if ( nError == ERRCODE_BASIC_OPER_NOT_PERFORM ) 1453 return 17; 1454 else if ( nError == ERRCODE_BASIC_TOO_MANY_DLL ) 1455 return 47; 1456 else if ( nError == ERRCODE_BASIC_LOOP_NOT_INIT ) 1457 return 92; 1458 else 1459 nRet = 0; 1460 } 1461 1462 // search loop 1463 const SFX_VB_ErrorItem* pErrItem; 1464 sal_uInt16 nIndex = 0; 1465 do 1466 { 1467 pErrItem = SFX_VB_ErrorTab + nIndex; 1468 if( pErrItem->nErrorSFX == nError ) 1469 { 1470 nRet = pErrItem->nErrorVB; 1471 break; 1472 } 1473 nIndex++; 1474 } 1475 while( pErrItem->nErrorVB != 0xFFFF ); // up to end mark 1476 return nRet; 1477 } 1478 1479 ErrCode StarBASIC::GetSfxFromVBError( sal_uInt16 nError ) 1480 { 1481 ErrCode nRet = ERRCODE_NONE; 1482 1483 if( SbiRuntime::isVBAEnabled() ) 1484 { 1485 switch( nError ) 1486 { 1487 case 1: 1488 case 2: 1489 case 4: 1490 case 8: 1491 case 12: 1492 case 73: 1493 return ERRCODE_NONE; 1494 case 10: 1495 return ERRCODE_BASIC_ARRAY_FIX; 1496 case 14: 1497 return ERRCODE_BASIC_STRING_OVERFLOW; 1498 case 16: 1499 return ERRCODE_BASIC_EXPR_TOO_COMPLEX; 1500 case 17: 1501 return ERRCODE_BASIC_OPER_NOT_PERFORM; 1502 case 47: 1503 return ERRCODE_BASIC_TOO_MANY_DLL; 1504 case 92: 1505 return ERRCODE_BASIC_LOOP_NOT_INIT; 1506 default: 1507 nRet = ERRCODE_NONE; 1508 } 1509 } 1510 const SFX_VB_ErrorItem* pErrItem; 1511 sal_uInt16 nIndex = 0; 1512 do 1513 { 1514 pErrItem = SFX_VB_ErrorTab + nIndex; 1515 if( pErrItem->nErrorVB == nError ) 1516 { 1517 nRet = pErrItem->nErrorSFX; 1518 break; 1519 } 1520 else if( pErrItem->nErrorVB > nError ) 1521 { 1522 break; // couldn't found anymore 1523 } 1524 nIndex++; 1525 } 1526 while( pErrItem->nErrorVB != 0xFFFF ); // up to end mark 1527 return nRet; 1528 } 1529 1530 // set Error- / Break-data 1531 void StarBASIC::SetErrorData( ErrCode nCode, sal_uInt16 nLine, 1532 sal_uInt16 nCol1, sal_uInt16 nCol2 ) 1533 { 1534 SbiGlobals& aGlobals = *GetSbData(); 1535 aGlobals.nCode = nCode; 1536 aGlobals.nLine = nLine; 1537 aGlobals.nCol1 = nCol1; 1538 aGlobals.nCol2 = nCol2; 1539 } 1540 1541 void StarBASIC::MakeErrorText( ErrCode nId, std::u16string_view aMsg ) 1542 { 1543 SolarMutexGuard aSolarGuard; 1544 sal_uInt16 nOldID = GetVBErrorCode( nId ); 1545 1546 TranslateId pErrorMsg; 1547 for (std::pair<TranslateId, ErrCode> const *pItem = RID_BASIC_START; pItem->second; ++pItem) 1548 { 1549 if (nId == pItem->second) 1550 { 1551 pErrorMsg = pItem->first; 1552 break; 1553 } 1554 } 1555 1556 if (pErrorMsg) 1557 { 1558 // merge message with additional text 1559 OUString sError = BasResId(pErrorMsg); 1560 OUStringBuffer aMsg1(sError); 1561 // replace argument placeholder with %s 1562 OUString aSrgStr( "$(ARG1)" ); 1563 sal_Int32 nResult = sError.indexOf(aSrgStr); 1564 1565 if( nResult >= 0 ) 1566 { 1567 aMsg1.remove(nResult, aSrgStr.getLength()); 1568 aMsg1.insert(nResult, aMsg); 1569 } 1570 GetSbData()->aErrMsg = aMsg1.makeStringAndClear(); 1571 } 1572 else if( nOldID != 0 ) 1573 { 1574 OUString aStdMsg = "Error " + OUString::number(nOldID) + 1575 ": No error text available!"; 1576 GetSbData()->aErrMsg = aStdMsg; 1577 } 1578 else 1579 { 1580 GetSbData()->aErrMsg.clear(); 1581 } 1582 } 1583 1584 bool StarBASIC::CError( ErrCode code, const OUString& rMsg, 1585 sal_Int32 l, sal_Int32 c1, sal_Int32 c2 ) 1586 { 1587 SolarMutexGuard aSolarGuard; 1588 1589 // compiler error during runtime -> stop program 1590 if( IsRunning() ) 1591 { 1592 // #109018 Check if running Basic is affected 1593 StarBASIC* pStartedBasic = GetSbData()->pInst->GetBasic(); 1594 if( pStartedBasic != this ) 1595 { 1596 return false; 1597 } 1598 Stop(); 1599 } 1600 1601 // set flag, so that GlobalRunInit notice the error 1602 GetSbData()->bGlobalInitErr = true; 1603 1604 // tinker the error message 1605 MakeErrorText( code, rMsg ); 1606 1607 // Implementation of the code for the string transport to SFX-Error 1608 if( !rMsg.isEmpty() ) 1609 { 1610 code = *new StringErrorInfo( code, rMsg ); 1611 } 1612 SetErrorData( code, l, c1, c2 ); 1613 GetSbData()->bCompilerError = true; 1614 bool bRet; 1615 if( GetSbData()->aErrHdl.IsSet() ) 1616 { 1617 bRet = GetSbData()->aErrHdl.Call( this ); 1618 } 1619 else 1620 { 1621 bRet = ErrorHdl(); 1622 } 1623 GetSbData()->bCompilerError = false; // only true for error handler 1624 return bRet; 1625 } 1626 1627 bool StarBASIC::RTError( ErrCode code, const OUString& rMsg, sal_Int32 l, sal_Int32 c1, sal_Int32 c2 ) 1628 { 1629 SolarMutexGuard aSolarGuard; 1630 1631 ErrCode c = code; 1632 if( c.GetClass() == ErrCodeClass::Compiler ) 1633 { 1634 c = ERRCODE_NONE; 1635 } 1636 MakeErrorText( c, rMsg ); 1637 1638 // Implementation of the code for the string transport to SFX-Error 1639 if( !rMsg.isEmpty() ) 1640 { 1641 // very confusing, even though MakeErrorText sets up the error text 1642 // seems that this is not used ( if rMsg already has content ) 1643 // In the case of VBA MakeErrorText also formats the error to be a little more 1644 // like vba ( adds an error number etc ) 1645 if ( SbiRuntime::isVBAEnabled() && ( code == ERRCODE_BASIC_COMPAT ) ) 1646 { 1647 OUString aTmp = "\'" + OUString::number(SbxErrObject::getUnoErrObject()->getNumber()) + 1648 "\'\n" + (!GetSbData()->aErrMsg.isEmpty() ? GetSbData()->aErrMsg : rMsg); 1649 code = *new StringErrorInfo( code, aTmp ); 1650 } 1651 else 1652 { 1653 code = *new StringErrorInfo( code, rMsg ); 1654 } 1655 } 1656 1657 SetErrorData( code, l, c1, c2 ); 1658 if( GetSbData()->aErrHdl.IsSet() ) 1659 { 1660 return GetSbData()->aErrHdl.Call( this ); 1661 } 1662 else 1663 { 1664 return ErrorHdl(); 1665 } 1666 } 1667 1668 void StarBASIC::Error( ErrCode n ) 1669 { 1670 Error( n, OUString() ); 1671 } 1672 1673 void StarBASIC::Error( ErrCode n, const OUString& rMsg ) 1674 { 1675 if( GetSbData()->pInst ) 1676 { 1677 GetSbData()->pInst->Error( n, rMsg ); 1678 } 1679 } 1680 1681 void StarBASIC::FatalError( ErrCode n ) 1682 { 1683 if( GetSbData()->pInst ) 1684 { 1685 GetSbData()->pInst->FatalError( n ); 1686 } 1687 } 1688 1689 void StarBASIC::FatalError( ErrCode _errCode, const OUString& _details ) 1690 { 1691 if( GetSbData()->pInst ) 1692 { 1693 GetSbData()->pInst->FatalError( _errCode, _details ); 1694 } 1695 } 1696 1697 ErrCode StarBASIC::GetErrBasic() 1698 { 1699 if( GetSbData()->pInst ) 1700 { 1701 return GetSbData()->pInst->GetErr(); 1702 } 1703 else 1704 { 1705 return ERRCODE_NONE; 1706 } 1707 } 1708 1709 // make the additional message for the RTL function error accessible 1710 OUString StarBASIC::GetErrorMsg() 1711 { 1712 if( GetSbData()->pInst ) 1713 { 1714 return GetSbData()->pInst->GetErrorMsg(); 1715 } 1716 else 1717 { 1718 return OUString(); 1719 } 1720 } 1721 1722 sal_Int32 StarBASIC::GetErl() 1723 { 1724 if( GetSbData()->pInst ) 1725 { 1726 return GetSbData()->pInst->GetErl(); 1727 } 1728 else 1729 { 1730 return 0; 1731 } 1732 } 1733 1734 bool StarBASIC::ErrorHdl() 1735 { 1736 return aErrorHdl.Call( this ); 1737 } 1738 1739 Link<StarBASIC*,bool> const & StarBASIC::GetGlobalErrorHdl() 1740 { 1741 return GetSbData()->aErrHdl; 1742 } 1743 1744 void StarBASIC::SetGlobalErrorHdl( const Link<StarBASIC*,bool>& rLink ) 1745 { 1746 GetSbData()->aErrHdl = rLink; 1747 } 1748 1749 void StarBASIC::SetGlobalBreakHdl( const Link<StarBASIC*,BasicDebugFlags>& rLink ) 1750 { 1751 GetSbData()->aBreakHdl = rLink; 1752 } 1753 1754 SbxArrayRef const & StarBASIC::getUnoListeners() 1755 { 1756 if( !xUnoListeners.is() ) 1757 { 1758 xUnoListeners = new SbxArray(); 1759 } 1760 return xUnoListeners; 1761 } 1762 1763 1764 bool StarBASIC::LoadData( SvStream& r, sal_uInt16 nVer ) 1765 { 1766 if( !SbxObject::LoadData( r, nVer ) ) 1767 { 1768 return false; 1769 } 1770 // #95459 Delete dialogs, otherwise endless recursion 1771 // in SbxVariable::GetType() if dialogs are accessed 1772 sal_uInt32 nObjCount = pObjs->Count(); 1773 std::unique_ptr<SbxVariable*[]> ppDeleteTab(new SbxVariable*[ nObjCount ]); 1774 sal_uInt32 nObj; 1775 1776 for( nObj = 0 ; nObj < nObjCount ; nObj++ ) 1777 { 1778 SbxVariable* pVar = pObjs->Get(nObj); 1779 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( pVar ); 1780 ppDeleteTab[nObj] = pBasic ? nullptr : pVar; 1781 } 1782 for( nObj = 0 ; nObj < nObjCount ; nObj++ ) 1783 { 1784 SbxVariable* pVar = ppDeleteTab[nObj]; 1785 if( pVar ) 1786 { 1787 pObjs->Remove( pVar ); 1788 } 1789 } 1790 ppDeleteTab.reset(); 1791 1792 sal_uInt16 nMod(0); 1793 pModules.clear(); 1794 r.ReadUInt16( nMod ); 1795 const size_t nMinSbxSize(14); 1796 const size_t nMaxPossibleEntries = r.remainingSize() / nMinSbxSize; 1797 if (nMod > nMaxPossibleEntries) 1798 { 1799 nMod = nMaxPossibleEntries; 1800 SAL_WARN("basic", "Parsing error: " << nMaxPossibleEntries << 1801 " max possible entries, but " << nMod << " claimed, truncating"); 1802 } 1803 for (sal_uInt16 i = 0; i < nMod; ++i) 1804 { 1805 SbxBaseRef pBase = SbxBase::Load( r ); 1806 SbModule* pMod = dynamic_cast<SbModule*>(pBase.get()); 1807 if( !pMod ) 1808 { 1809 return false; 1810 } 1811 else if( dynamic_cast<const SbJScriptModule*>( pMod) != nullptr ) 1812 { 1813 // assign Ref, so that pMod will be deleted 1814 SbModuleRef xDeleteRef = pMod; 1815 } 1816 else 1817 { 1818 pMod->SetParent( this ); 1819 pModules.emplace_back(pMod ); 1820 } 1821 } 1822 // HACK for SFX-Bullshit! 1823 SbxVariable* p = Find( "FALSE", SbxClassType::Property ); 1824 if( p ) 1825 { 1826 Remove( p ); 1827 } 1828 p = Find( "TRUE", SbxClassType::Property ); 1829 if( p ) 1830 { 1831 Remove( p ); 1832 } 1833 // End of the hacks! 1834 // Search via StarBASIC is at all times global 1835 DBG_ASSERT( IsSet( SbxFlagBits::GlobalSearch ), "Basic loaded without GBLSEARCH" ); 1836 SetFlag( SbxFlagBits::GlobalSearch ); 1837 return true; 1838 } 1839 1840 bool StarBASIC::StoreData( SvStream& r ) const 1841 { 1842 if( !SbxObject::StoreData( r ) ) 1843 { 1844 return false; 1845 } 1846 assert(pModules.size() < SAL_MAX_UINT16); 1847 r.WriteUInt16( static_cast<sal_uInt16>(pModules.size())); 1848 for( const auto& rpModule: pModules ) 1849 { 1850 if( !rpModule->Store( r ) ) 1851 { 1852 return false; 1853 } 1854 } 1855 return true; 1856 } 1857 1858 bool StarBASIC::GetUNOConstant( const OUString& rName, css::uno::Any& aOut ) 1859 { 1860 bool bRes = false; 1861 SbUnoObject* pGlobs = dynamic_cast<SbUnoObject*>( Find( rName, SbxClassType::DontCare ) ); 1862 if ( pGlobs ) 1863 { 1864 aOut = pGlobs->getUnoAny(); 1865 bRes = true; 1866 } 1867 return bRes; 1868 } 1869 1870 Reference< frame::XModel > StarBASIC::GetModelFromBasic( SbxObject* pBasic ) 1871 { 1872 OSL_PRECOND( pBasic != nullptr, "getModelFromBasic: illegal call!" ); 1873 if ( !pBasic ) 1874 { 1875 return nullptr; 1876 } 1877 // look for the ThisComponent variable, first in the parent (which 1878 // might be the document's Basic), then in the parent's parent (which might be 1879 // the application Basic) 1880 static const OUStringLiteral sThisComponent( u"ThisComponent"); 1881 SbxVariable* pThisComponent = nullptr; 1882 1883 SbxObject* pLookup = pBasic->GetParent(); 1884 while ( pLookup && !pThisComponent ) 1885 { 1886 pThisComponent = pLookup->Find( sThisComponent, SbxClassType::Object ); 1887 pLookup = pLookup->GetParent(); 1888 } 1889 if ( !pThisComponent ) 1890 { 1891 SAL_WARN("basic", "Failed to get ThisComponent"); 1892 // the application Basic, at the latest, should have this variable 1893 return nullptr; 1894 } 1895 1896 Any aThisComponentAny( sbxToUnoValue( pThisComponent ) ); 1897 Reference< frame::XModel > xModel( aThisComponentAny, UNO_QUERY ); 1898 if ( !xModel.is() ) 1899 { 1900 // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller. 1901 Reference< frame::XController > xController( aThisComponentAny, UNO_QUERY ); 1902 if ( xController.is() ) 1903 { 1904 xModel = xController->getModel(); 1905 } 1906 } 1907 if ( !xModel.is() ) 1908 { 1909 return nullptr; 1910 } 1911 1912 return xModel; 1913 } 1914 1915 void StarBASIC::DetachAllDocBasicItems() 1916 { 1917 for (auto const& item : gaDocBasicItems) 1918 { 1919 DocBasicItemRef xItem = item.second; 1920 xItem->setDisposed(true); 1921 } 1922 } 1923 1924 // #118116 Implementation Collection object 1925 1926 1927 constexpr OUStringLiteral pCountStr = u"Count"; 1928 constexpr OUStringLiteral pAddStr = u"Add"; 1929 constexpr OUStringLiteral pItemStr = u"Item"; 1930 constexpr OUStringLiteral pRemoveStr = u"Remove"; 1931 constexpr sal_uInt16 nCountHash = SbxVariable::MakeHashCode(pCountStr); 1932 constexpr sal_uInt16 nAddHash = SbxVariable::MakeHashCode(pAddStr); 1933 constexpr sal_uInt16 nItemHash = SbxVariable::MakeHashCode(pItemStr); 1934 constexpr sal_uInt16 nRemoveHash = SbxVariable::MakeHashCode(pRemoveStr); 1935 1936 SbxInfoRef BasicCollection::xAddInfo; 1937 SbxInfoRef BasicCollection::xItemInfo; 1938 1939 BasicCollection::BasicCollection( const OUString& rClass ) 1940 : SbxObject( rClass ) 1941 { 1942 Initialize(); 1943 } 1944 1945 BasicCollection::~BasicCollection() 1946 {} 1947 1948 void BasicCollection::Clear() 1949 { 1950 SbxObject::Clear(); 1951 Initialize(); 1952 } 1953 1954 void BasicCollection::Initialize() 1955 { 1956 xItemArray = new SbxArray(); 1957 SetType( SbxOBJECT ); 1958 SetFlag( SbxFlagBits::Fixed ); 1959 ResetFlag( SbxFlagBits::Write ); 1960 SbxVariable* p; 1961 p = Make( pCountStr, SbxClassType::Property, SbxINTEGER ); 1962 p->ResetFlag( SbxFlagBits::Write ); 1963 p->SetFlag( SbxFlagBits::DontStore ); 1964 p = Make( pAddStr, SbxClassType::Method, SbxEMPTY ); 1965 p->SetFlag( SbxFlagBits::DontStore ); 1966 p = Make( pItemStr, SbxClassType::Method, SbxVARIANT ); 1967 p->SetFlag( SbxFlagBits::DontStore ); 1968 p = Make( pRemoveStr, SbxClassType::Method, SbxEMPTY ); 1969 p->SetFlag( SbxFlagBits::DontStore ); 1970 if ( !xAddInfo.is() ) 1971 { 1972 xAddInfo = new SbxInfo; 1973 xAddInfo->AddParam( "Item", SbxVARIANT ); 1974 xAddInfo->AddParam( "Key", SbxVARIANT, SbxFlagBits::Read | SbxFlagBits::Optional ); 1975 xAddInfo->AddParam( "Before", SbxVARIANT, SbxFlagBits::Read | SbxFlagBits::Optional ); 1976 xAddInfo->AddParam( "After", SbxVARIANT, SbxFlagBits::Read | SbxFlagBits::Optional ); 1977 } 1978 if ( !xItemInfo.is() ) 1979 { 1980 xItemInfo = new SbxInfo; 1981 xItemInfo->AddParam( "Index", SbxVARIANT, SbxFlagBits::Read | SbxFlagBits::Optional); 1982 } 1983 } 1984 1985 void BasicCollection::Notify( SfxBroadcaster& rCst, const SfxHint& rHint ) 1986 { 1987 const SbxHint* p = dynamic_cast<const SbxHint*>(&rHint); 1988 if( p ) 1989 { 1990 const SfxHintId nId = p->GetId(); 1991 bool bRead = nId == SfxHintId::BasicDataWanted; 1992 bool bWrite = nId == SfxHintId::BasicDataChanged; 1993 bool bRequestInfo = nId == SfxHintId::BasicInfoWanted; 1994 SbxVariable* pVar = p->GetVar(); 1995 SbxArray* pArg = pVar->GetParameters(); 1996 OUString aVarName( pVar->GetName() ); 1997 if( bRead || bWrite ) 1998 { 1999 if( pVar->GetHashCode() == nCountHash 2000 && aVarName.equalsIgnoreAsciiCase( pCountStr ) ) 2001 { 2002 pVar->PutLong(xItemArray->Count()); 2003 } 2004 else if( pVar->GetHashCode() == nAddHash 2005 && aVarName.equalsIgnoreAsciiCase( pAddStr ) ) 2006 { 2007 CollAdd( pArg ); 2008 } 2009 else if( pVar->GetHashCode() == nItemHash 2010 && aVarName.equalsIgnoreAsciiCase( pItemStr ) ) 2011 { 2012 CollItem( pArg ); 2013 } 2014 else if( pVar->GetHashCode() == nRemoveHash 2015 && aVarName.equalsIgnoreAsciiCase( pRemoveStr ) ) 2016 { 2017 CollRemove( pArg ); 2018 } 2019 else 2020 { 2021 SbxObject::Notify( rCst, rHint ); 2022 } 2023 return; 2024 } 2025 else if ( bRequestInfo ) 2026 { 2027 if( pVar->GetHashCode() == nAddHash 2028 && aVarName.equalsIgnoreAsciiCase( pAddStr ) ) 2029 { 2030 pVar->SetInfo( xAddInfo.get() ); 2031 } 2032 else if( pVar->GetHashCode() == nItemHash 2033 && aVarName.equalsIgnoreAsciiCase( pItemStr ) ) 2034 { 2035 pVar->SetInfo( xItemInfo.get() ); 2036 } 2037 } 2038 } 2039 SbxObject::Notify( rCst, rHint ); 2040 } 2041 2042 sal_Int32 BasicCollection::implGetIndex( SbxVariable const * pIndexVar ) 2043 { 2044 sal_Int32 nIndex = -1; 2045 if( pIndexVar->GetType() == SbxSTRING ) 2046 { 2047 nIndex = implGetIndexForName( pIndexVar->GetOUString() ); 2048 } 2049 else 2050 { 2051 nIndex = pIndexVar->GetLong() - 1; 2052 } 2053 return nIndex; 2054 } 2055 2056 sal_Int32 BasicCollection::implGetIndexForName(std::u16string_view rName) 2057 { 2058 sal_Int32 nIndex = -1; 2059 sal_Int32 nCount = xItemArray->Count(); 2060 sal_Int32 nNameHash = MakeHashCode( rName ); 2061 for( sal_Int32 i = 0 ; i < nCount ; i++ ) 2062 { 2063 SbxVariable* pVar = xItemArray->Get(i); 2064 if( pVar->GetHashCode() == nNameHash && 2065 pVar->GetName().equalsIgnoreAsciiCase( rName ) ) 2066 { 2067 nIndex = i; 2068 break; 2069 } 2070 } 2071 return nIndex; 2072 } 2073 2074 void BasicCollection::CollAdd( SbxArray* pPar_ ) 2075 { 2076 sal_uInt32 nCount = pPar_->Count(); 2077 if( nCount < 2 || nCount > 5 ) 2078 { 2079 SetError( ERRCODE_BASIC_WRONG_ARGS ); 2080 return; 2081 } 2082 2083 SbxVariable* pItem = pPar_->Get(1); 2084 if( pItem ) 2085 { 2086 sal_uInt32 nNextIndex; 2087 if( nCount < 4 ) 2088 { 2089 nNextIndex = xItemArray->Count(); 2090 } 2091 else 2092 { 2093 SbxVariable* pBefore = pPar_->Get(3); 2094 if( nCount == 5 ) 2095 { 2096 if( !( pBefore->IsErr() || ( pBefore->GetType() == SbxEMPTY ) ) ) 2097 { 2098 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2099 return; 2100 } 2101 SbxVariable* pAfter = pPar_->Get(4); 2102 sal_Int32 nAfterIndex = implGetIndex( pAfter ); 2103 if( nAfterIndex == -1 ) 2104 { 2105 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2106 return; 2107 } 2108 nNextIndex = sal::static_int_cast<sal_uInt32>(nAfterIndex + 1); 2109 } 2110 else // if( nCount == 4 ) 2111 { 2112 sal_Int32 nBeforeIndex = implGetIndex( pBefore ); 2113 if( nBeforeIndex == -1 ) 2114 { 2115 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2116 return; 2117 } 2118 nNextIndex = sal::static_int_cast<sal_uInt32>(nBeforeIndex); 2119 } 2120 } 2121 2122 auto pNewItem = tools::make_ref<SbxVariable>( *pItem ); 2123 if( nCount >= 3 ) 2124 { 2125 SbxVariable* pKey = pPar_->Get(2); 2126 if( !( pKey->IsErr() || ( pKey->GetType() == SbxEMPTY ) ) ) 2127 { 2128 if( pKey->GetType() != SbxSTRING ) 2129 { 2130 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2131 return; 2132 } 2133 OUString aKey = pKey->GetOUString(); 2134 if( implGetIndexForName( aKey ) != -1 ) 2135 { 2136 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2137 return; 2138 } 2139 pNewItem->SetName( aKey ); 2140 } 2141 } 2142 pNewItem->SetFlag( SbxFlagBits::ReadWrite ); 2143 xItemArray->Insert(pNewItem.get(), nNextIndex); 2144 } 2145 else 2146 { 2147 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2148 return; 2149 } 2150 } 2151 2152 void BasicCollection::CollItem( SbxArray* pPar_ ) 2153 { 2154 if (pPar_->Count() != 2) 2155 { 2156 SetError( ERRCODE_BASIC_WRONG_ARGS ); 2157 return; 2158 } 2159 SbxVariable* pRes = nullptr; 2160 SbxVariable* p = pPar_->Get(1); 2161 sal_Int32 nIndex = implGetIndex( p ); 2162 if (nIndex >= 0 && nIndex < static_cast<sal_Int32>(xItemArray->Count())) 2163 { 2164 pRes = xItemArray->Get(nIndex); 2165 } 2166 if( !pRes ) 2167 { 2168 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2169 } 2170 else 2171 { 2172 *(pPar_->Get(0)) = *pRes; 2173 } 2174 } 2175 2176 void BasicCollection::CollRemove( SbxArray* pPar_ ) 2177 { 2178 if (pPar_ == nullptr || pPar_->Count() != 2) 2179 { 2180 SetError( ERRCODE_BASIC_WRONG_ARGS ); 2181 return; 2182 } 2183 2184 SbxVariable* p = pPar_->Get(1); 2185 sal_Int32 nIndex = implGetIndex( p ); 2186 if (nIndex >= 0 && nIndex < static_cast<sal_Int32>(xItemArray->Count())) 2187 { 2188 xItemArray->Remove( nIndex ); 2189 2190 // Correct for stack if necessary 2191 SbiInstance* pInst = GetSbData()->pInst; 2192 SbiRuntime* pRT = pInst ? pInst->pRun : nullptr; 2193 if( pRT ) 2194 { 2195 SbiForStack* pStack = pRT->FindForStackItemForCollection( this ); 2196 if( pStack != nullptr ) 2197 { 2198 if( pStack->nCurCollectionIndex >= nIndex ) 2199 { 2200 --pStack->nCurCollectionIndex; 2201 } 2202 } 2203 } 2204 } 2205 else 2206 { 2207 SetError( ERRCODE_BASIC_BAD_ARGUMENT ); 2208 } 2209 } 2210 2211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2212
