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