xref: /core/basic/source/basmgr/basmgr.cxx (revision 754c6af4)
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 <vcl/errinf.hxx>
21 #include <tools/stream.hxx>
22 #include <sot/storage.hxx>
23 #include <tools/urlobj.hxx>
24 #include <svl/hint.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/window.hxx>
27 #include <vcl/wrkwin.hxx>
28 #include <basic/sbx.hxx>
29 #include <sot/storinfo.hxx>
30 #include <unotools/pathoptions.hxx>
31 #include <tools/debug.hxx>
32 #include <tools/diagnose_ex.h>
33 #include <basic/sbmod.hxx>
34 #include <unotools/intlwrapper.hxx>
35 #include <sal/log.hxx>
36 
37 #include <basic/sbuno.hxx>
38 #include <basic/basmgr.hxx>
39 #include <global.hxx>
40 #include <sbunoobj.hxx>
41 #include <sbintern.hxx>
42 #include <com/sun/star/script/XLibraryContainer.hpp>
43 #include <com/sun/star/script/XPersistentLibraryContainer.hpp>
44 
45 #include <memory>
46 #include <vector>
47 
48 #define LIB_SEP         0x01
49 #define LIBINFO_SEP     0x02
50 #define LIBINFO_ID      0x1491
51 #define PASSWORD_MARKER 0x31452134
52 
53 
54 // Library API, implemented for XML import/export
55 
56 #include <com/sun/star/container/XNameContainer.hpp>
57 #include <com/sun/star/container/XContainer.hpp>
58 #include <com/sun/star/script/XStarBasicAccess.hpp>
59 #include <com/sun/star/script/XStarBasicModuleInfo.hpp>
60 #include <com/sun/star/script/XStarBasicDialogInfo.hpp>
61 #include <com/sun/star/script/XStarBasicLibraryInfo.hpp>
62 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
63 #include <com/sun/star/script/ModuleInfo.hpp>
64 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
65 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
66 #include <com/sun/star/ucb/ContentCreationException.hpp>
67 
68 #include <cppuhelper/implbase.hxx>
69 
70 using com::sun::star::uno::Reference;
71 using namespace com::sun::star;
72 using namespace com::sun::star::script;
73 using namespace cppu;
74 
75 typedef WeakImplHelper< container::XNameContainer > NameContainerHelper;
76 typedef WeakImplHelper< script::XStarBasicModuleInfo > ModuleInfoHelper;
77 typedef WeakImplHelper< script::XStarBasicAccess > StarBasicAccessHelper;
78 
79 // Version 1
80 //    sal_uInt32    nEndPos
81 //    sal_uInt16    nId
82 //    sal_uInt16    nVer
83 //    bool      bDoLoad
84 //    String    LibName
85 //    String    AbsStorageName
86 //    String    RelStorageName
87 // Version 2
88 //  + bool      bReference
89 
90 static const char szStdLibName[] = "Standard";
91 static const char szBasicStorage[] = "StarBASIC";
92 static const char szOldManagerStream[] = "BasicManager";
93 static const char szManagerStream[] = "BasicManager2";
94 static const char szImbedded[] = "LIBIMBEDDED";
95 static const char szCryptingKey[] = "CryptedBasic";
96 
97 
98 const StreamMode eStreamReadMode = StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL;
99 const StreamMode eStorageReadMode = StreamMode::READ | StreamMode::SHARE_DENYWRITE;
100 
101 
102 // BasicManager impl data
103 struct BasicManagerImpl
104 {
105     LibraryContainerInfo    maContainerInfo;
106 
107     std::vector<std::unique_ptr<BasicLibInfo>> aLibs;
108     OUString         aBasicLibPath;
109 
110     BasicManagerImpl()
111     {}
112 };
113 
114 // BasMgrContainerListenerImpl
115 
116 
117 typedef ::cppu::WeakImplHelper< container::XContainerListener > ContainerListenerHelper;
118 
119 class BasMgrContainerListenerImpl: public ContainerListenerHelper
120 {
121     BasicManager* mpMgr;
122     OUString maLibName;      // empty -> no lib, but lib container
123 
124 public:
125     BasMgrContainerListenerImpl( BasicManager* pMgr, const OUString& aLibName )
126         : mpMgr( pMgr )
127         , maLibName( aLibName ) {}
128 
129     static void insertLibraryImpl( const uno::Reference< script::XLibraryContainer >& xScriptCont, BasicManager* pMgr,
130                                    const uno::Any& aLibAny, const OUString& aLibName );
131     static void addLibraryModulesImpl( BasicManager const * pMgr, const uno::Reference< container::XNameAccess >& xLibNameAccess,
132                                        const OUString& aLibName );
133 
134 
135     // XEventListener
136     virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
137 
138     // XContainerListener
139     virtual void SAL_CALL elementInserted( const container::ContainerEvent& Event ) override;
140     virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) override;
141     virtual void SAL_CALL elementRemoved( const container::ContainerEvent& Event ) override;
142 };
143 
144 
145 // BasMgrContainerListenerImpl
146 
147 
148 void BasMgrContainerListenerImpl::insertLibraryImpl( const uno::Reference< script::XLibraryContainer >& xScriptCont,
149     BasicManager* pMgr, const uno::Any& aLibAny, const OUString& aLibName )
150 {
151     Reference< container::XNameAccess > xLibNameAccess;
152     aLibAny >>= xLibNameAccess;
153 
154     if( !pMgr->GetLib( aLibName ) )
155     {
156         StarBASIC* pLib =
157             pMgr->CreateLibForLibContainer( aLibName, xScriptCont );
158         DBG_ASSERT( pLib, "XML Import: Basic library could not be created");
159     }
160 
161     uno::Reference< container::XContainer> xLibContainer( xLibNameAccess, uno::UNO_QUERY );
162     if( xLibContainer.is() )
163     {
164         // Register listener for library
165         Reference< container::XContainerListener > xLibraryListener
166             = new BasMgrContainerListenerImpl( pMgr, aLibName );
167         xLibContainer->addContainerListener( xLibraryListener );
168     }
169 
170     if( xScriptCont->isLibraryLoaded( aLibName ) )
171     {
172         addLibraryModulesImpl( pMgr, xLibNameAccess, aLibName );
173     }
174 }
175 
176 
177 void BasMgrContainerListenerImpl::addLibraryModulesImpl( BasicManager const * pMgr,
178     const uno::Reference< container::XNameAccess >& xLibNameAccess, const OUString& aLibName )
179 {
180     uno::Sequence< OUString > aModuleNames = xLibNameAccess->getElementNames();
181     sal_Int32 nModuleCount = aModuleNames.getLength();
182 
183     StarBASIC* pLib = pMgr->GetLib( aLibName );
184     DBG_ASSERT( pLib, "BasMgrContainerListenerImpl::addLibraryModulesImpl: Unknown lib!");
185     if( pLib )
186     {
187         const OUString* pNames = aModuleNames.getConstArray();
188         for( sal_Int32 j = 0 ; j < nModuleCount ; j++ )
189         {
190             OUString aModuleName = pNames[ j ];
191             uno::Any aElement = xLibNameAccess->getByName( aModuleName );
192             OUString aMod;
193             aElement >>= aMod;
194             uno::Reference< vba::XVBAModuleInfo > xVBAModuleInfo( xLibNameAccess, uno::UNO_QUERY );
195             if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( aModuleName ) )
196             {
197                 ModuleInfo aInfo = xVBAModuleInfo->getModuleInfo( aModuleName );
198                 pLib->MakeModule( aModuleName, aInfo, aMod );
199             }
200             else
201         pLib->MakeModule( aModuleName, aMod );
202         }
203 
204         pLib->SetModified( false );
205     }
206 }
207 
208 
209 // XEventListener
210 
211 
212 void SAL_CALL BasMgrContainerListenerImpl::disposing( const lang::EventObject& ) {}
213 
214 // XContainerListener
215 
216 
217 void SAL_CALL BasMgrContainerListenerImpl::elementInserted( const container::ContainerEvent& Event )
218 {
219     bool bLibContainer = maLibName.isEmpty();
220     OUString aName;
221     Event.Accessor >>= aName;
222 
223     if( bLibContainer )
224     {
225         uno::Reference< script::XLibraryContainer > xScriptCont( Event.Source, uno::UNO_QUERY );
226         if (xScriptCont.is())
227             insertLibraryImpl(xScriptCont, mpMgr, Event.Element, aName);
228         StarBASIC* pLib = mpMgr->GetLib( aName );
229         if ( pLib )
230         {
231             uno::Reference< vba::XVBACompatibility > xVBACompat( xScriptCont, uno::UNO_QUERY );
232             if ( xVBACompat.is() )
233                 pLib->SetVBAEnabled( xVBACompat->getVBACompatibilityMode() );
234         }
235     }
236     else
237     {
238 
239         StarBASIC* pLib = mpMgr->GetLib( maLibName );
240         DBG_ASSERT( pLib, "BasMgrContainerListenerImpl::elementInserted: Unknown lib!");
241         if( pLib )
242         {
243             SbModule* pMod = pLib->FindModule( aName );
244             if( !pMod )
245             {
246                 OUString aMod;
247                 Event.Element >>= aMod;
248                 uno::Reference< vba::XVBAModuleInfo > xVBAModuleInfo( Event.Source, uno::UNO_QUERY );
249                 if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( aName ) )
250                 {
251                     ModuleInfo aInfo = xVBAModuleInfo->getModuleInfo( aName );
252                     pLib->MakeModule( aName, aInfo, aMod );
253                 }
254                 else
255                     pLib->MakeModule( aName, aMod );
256                 pLib->SetModified( false );
257             }
258         }
259     }
260 }
261 
262 
263 void SAL_CALL BasMgrContainerListenerImpl::elementReplaced( const container::ContainerEvent& Event )
264 {
265     OUString aName;
266     Event.Accessor >>= aName;
267 
268     // Replace not possible for library container
269     DBG_ASSERT( !maLibName.isEmpty(), "library container fired elementReplaced()");
270 
271     StarBASIC* pLib = mpMgr->GetLib( maLibName );
272     if( pLib )
273     {
274         SbModule* pMod = pLib->FindModule( aName );
275         OUString aMod;
276         Event.Element >>= aMod;
277 
278         if( pMod )
279                 pMod->SetSource32( aMod );
280         else
281                 pLib->MakeModule( aName, aMod );
282 
283         pLib->SetModified( false );
284     }
285 }
286 
287 
288 void SAL_CALL BasMgrContainerListenerImpl::elementRemoved( const container::ContainerEvent& Event )
289 {
290     OUString aName;
291     Event.Accessor >>= aName;
292 
293     bool bLibContainer = maLibName.isEmpty();
294     if( bLibContainer )
295     {
296         StarBASIC* pLib = mpMgr->GetLib( aName );
297         if( pLib )
298         {
299             sal_uInt16 nLibId = mpMgr->GetLibId( aName );
300             mpMgr->RemoveLib( nLibId, false );
301         }
302     }
303     else
304     {
305         StarBASIC* pLib = mpMgr->GetLib( maLibName );
306         SbModule* pMod = pLib ? pLib->FindModule( aName ) : nullptr;
307         if( pMod )
308         {
309             pLib->Remove( pMod );
310             pLib->SetModified( false );
311         }
312     }
313 }
314 
315 BasicError::BasicError( ErrCode nId, BasicErrorReason nR )
316 {
317     nErrorId    = nId;
318     nReason     = nR;
319 }
320 
321 BasicError::BasicError( const BasicError& rErr )
322 {
323     nErrorId    = rErr.nErrorId;
324     nReason     = rErr.nReason;
325 }
326 
327 
328 class BasicLibInfo
329 {
330 private:
331     StarBASICRef    xLib;
332     OUString          aLibName;
333     OUString          aStorageName;   // string is sufficient, unique at runtime
334     OUString          aRelStorageName;
335     OUString          aPassword;
336 
337     bool              bDoLoad;
338     bool              bReference;
339 
340     // Lib represents library in new UNO library container
341     uno::Reference< script::XLibraryContainer > mxScriptCont;
342 
343 public:
344     BasicLibInfo();
345 
346     bool              IsReference() const     { return bReference; }
347     void              SetReference(bool b)    { bReference = b; }
348 
349     bool              IsExtern() const        { return aStorageName != szImbedded; }
350 
351     void              SetStorageName( const OUString& rName )   { aStorageName = rName; }
352     const OUString&   GetStorageName() const                  { return aStorageName; }
353 
354     void              SetRelStorageName( const OUString& rN )   { aRelStorageName = rN; }
355     const OUString&   GetRelStorageName() const               { return aRelStorageName; }
356 
357     StarBASICRef      GetLib() const
358     {
359         if( mxScriptCont.is() && mxScriptCont->hasByName( aLibName ) &&
360             !mxScriptCont->isLibraryLoaded( aLibName ) )
361                 return StarBASICRef();
362         return xLib;
363     }
364     StarBASICRef&     GetLibRef()                         { return xLib; }
365     void              SetLib( StarBASIC* pBasic )         { xLib = pBasic; }
366 
367     const OUString&   GetLibName() const                  { return aLibName; }
368     void              SetLibName( const OUString& rName )   { aLibName = rName; }
369 
370     // Only temporary for Load/Save
371     bool              DoLoad()                            { return bDoLoad; }
372 
373     bool              HasPassword() const                 { return !aPassword.isEmpty(); }
374     const OUString&   GetPassword() const                 { return aPassword; }
375     void              SetPassword( const OUString& rNewPassword )
376                                                         { aPassword = rNewPassword; }
377 
378     static BasicLibInfo*    Create( SotStorageStream& rSStream );
379 
380     const uno::Reference< script::XLibraryContainer >& GetLibraryContainer()
381         { return mxScriptCont; }
382     void SetLibraryContainer( const uno::Reference< script::XLibraryContainer >& xScriptCont )
383         { mxScriptCont = xScriptCont; }
384 };
385 
386 
387 BasicLibInfo::BasicLibInfo()
388     : aStorageName(szImbedded)
389     , aRelStorageName(szImbedded)
390     , bDoLoad(false)
391     , bReference(false)
392 {
393 }
394 
395 BasicLibInfo* BasicLibInfo::Create( SotStorageStream& rSStream )
396 {
397     BasicLibInfo* pInfo = new BasicLibInfo;
398 
399     sal_uInt32 nEndPos;
400     sal_uInt16 nId;
401     sal_uInt16 nVer;
402 
403     rSStream.ReadUInt32( nEndPos );
404     rSStream.ReadUInt16( nId );
405     rSStream.ReadUInt16( nVer );
406 
407     DBG_ASSERT( nId == LIBINFO_ID, "No BasicLibInfo?!" );
408     if( nId == LIBINFO_ID )
409     {
410         // Reload?
411         bool bDoLoad;
412         rSStream.ReadCharAsBool( bDoLoad );
413         pInfo->bDoLoad = bDoLoad;
414 
415         // The name of the lib...
416         OUString aName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
417         pInfo->SetLibName( aName );
418 
419         // Absolute path...
420         OUString aStorageName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
421         pInfo->SetStorageName( aStorageName );
422 
423         // Relative path...
424         OUString aRelStorageName = rSStream.ReadUniOrByteString(rSStream.GetStreamCharSet());
425         pInfo->SetRelStorageName( aRelStorageName );
426 
427         if ( nVer >= 2 )
428         {
429             bool bReferenz;
430             rSStream.ReadCharAsBool( bReferenz );
431             pInfo->SetReference(bReferenz);
432         }
433 
434         rSStream.Seek( nEndPos );
435     }
436     return pInfo;
437 }
438 
439 BasicManager::BasicManager( SotStorage& rStorage, const OUString& rBaseURL, StarBASIC* pParentFromStdLib, OUString const * pLibPath, bool bDocMgr ) : mbDocMgr( bDocMgr )
440 {
441     Init();
442 
443     if( pLibPath )
444     {
445         mpImpl->aBasicLibPath = *pLibPath;
446     }
447     OUString aStorName( rStorage.GetName() );
448     maStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
449 
450 
451     // If there is no Manager Stream, no further actions are necessary
452     if ( rStorage.IsStream( szManagerStream ) )
453     {
454         LoadBasicManager( rStorage, rBaseURL );
455         // StdLib contains Parent:
456         StarBASIC* pStdLib = GetStdLib();
457         DBG_ASSERT( pStdLib, "Standard-Lib not loaded?" );
458         if ( !pStdLib )
459         {
460             // Should never happen, but if it happens we won't crash...
461             pStdLib = new StarBASIC( nullptr, mbDocMgr );
462 
463             if (mpImpl->aLibs.empty())
464                 CreateLibInfo();
465 
466             BasicLibInfo& rStdLibInfo = *mpImpl->aLibs.front();
467 
468             rStdLibInfo.SetLib( pStdLib );
469             StarBASICRef xStdLib = rStdLibInfo.GetLib();
470             xStdLib->SetName( szStdLibName );
471             rStdLibInfo.SetLibName( szStdLibName );
472             xStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
473             xStdLib->SetModified( false );
474         }
475         else
476         {
477             pStdLib->SetParent( pParentFromStdLib );
478             // The other get StdLib as parent:
479 
480             for ( sal_uInt16 nBasic = 1; nBasic < GetLibCount(); nBasic++ )
481             {
482                 StarBASIC* pBasic = GetLib( nBasic );
483                 if ( pBasic )
484                 {
485                     pStdLib->Insert( pBasic );
486                     pBasic->SetFlag( SbxFlagBits::ExtSearch );
487                 }
488             }
489             // Modified through insert
490             pStdLib->SetModified( false );
491         }
492     }
493     else
494     {
495         ImpCreateStdLib( pParentFromStdLib );
496         if ( rStorage.IsStream( szOldManagerStream ) )
497             LoadOldBasicManager( rStorage );
498     }
499 }
500 
501 static void copyToLibraryContainer( StarBASIC* pBasic, const LibraryContainerInfo& rInfo )
502 {
503     uno::Reference< script::XLibraryContainer > xScriptCont( rInfo.mxScriptCont.get() );
504     if ( !xScriptCont.is() )
505         return;
506 
507     OUString aLibName = pBasic->GetName();
508     if( !xScriptCont->hasByName( aLibName ) )
509         xScriptCont->createLibrary( aLibName );
510 
511     uno::Any aLibAny = xScriptCont->getByName( aLibName );
512     uno::Reference< container::XNameContainer > xLib;
513     aLibAny >>= xLib;
514     if ( !xLib.is() )
515         return;
516 
517     for ( const auto& pModule: pBasic->GetModules() )
518     {
519         OUString aModName = pModule->GetName();
520         if( !xLib->hasByName( aModName ) )
521         {
522             OUString aSource = pModule->GetSource32();
523             uno::Any aSourceAny;
524             aSourceAny <<= aSource;
525             xLib->insertByName( aModName, aSourceAny );
526         }
527     }
528 }
529 
530 const uno::Reference< script::XPersistentLibraryContainer >& BasicManager::GetDialogLibraryContainer()  const
531 {
532     return mpImpl->maContainerInfo.mxDialogCont;
533 }
534 
535 const uno::Reference< script::XPersistentLibraryContainer >& BasicManager::GetScriptLibraryContainer()  const
536 {
537     return mpImpl->maContainerInfo.mxScriptCont;
538 }
539 
540 void BasicManager::SetLibraryContainerInfo( const LibraryContainerInfo& rInfo )
541 {
542     mpImpl->maContainerInfo = rInfo;
543 
544     uno::Reference< script::XLibraryContainer > xScriptCont( mpImpl->maContainerInfo.mxScriptCont.get() );
545     if( xScriptCont.is() )
546     {
547         // Register listener for lib container
548         uno::Reference< container::XContainerListener > xLibContainerListener
549             = new BasMgrContainerListenerImpl( this, "" );
550 
551         uno::Reference< container::XContainer> xLibContainer( xScriptCont, uno::UNO_QUERY );
552         xLibContainer->addContainerListener( xLibContainerListener );
553 
554         uno::Sequence< OUString > aScriptLibNames = xScriptCont->getElementNames();
555 
556         if( aScriptLibNames.hasElements() )
557         {
558             for(const auto& rScriptLibName : aScriptLibNames)
559             {
560                 uno::Any aLibAny = xScriptCont->getByName( rScriptLibName );
561 
562                 if ( rScriptLibName == "Standard" || rScriptLibName == "VBAProject")
563                     xScriptCont->loadLibrary( rScriptLibName );
564 
565                 BasMgrContainerListenerImpl::insertLibraryImpl
566                     ( xScriptCont, this, aLibAny, rScriptLibName );
567             }
568         }
569         else
570         {
571             // No libs? Maybe an 5.2 document already loaded
572             for (auto const& rpBasLibInfo : mpImpl->aLibs)
573             {
574                 StarBASIC* pLib = rpBasLibInfo->GetLib().get();
575                 if( !pLib )
576                 {
577                     bool bLoaded = ImpLoadLibrary( rpBasLibInfo.get(), nullptr );
578                     if( bLoaded )
579                         pLib = rpBasLibInfo->GetLib().get();
580                 }
581                 if( pLib )
582                 {
583                     copyToLibraryContainer( pLib, mpImpl->maContainerInfo );
584                     if (rpBasLibInfo->HasPassword())
585                     {
586                         OldBasicPassword* pOldBasicPassword =
587                             mpImpl->maContainerInfo.mpOldBasicPassword;
588                         if( pOldBasicPassword )
589                         {
590                             pOldBasicPassword->setLibraryPassword(
591                                 pLib->GetName(), rpBasLibInfo->GetPassword() );
592                         }
593                     }
594                 }
595             }
596         }
597     }
598 
599     SetGlobalUNOConstant( "BasicLibraries", uno::Any( mpImpl->maContainerInfo.mxScriptCont ) );
600     SetGlobalUNOConstant( "DialogLibraries", uno::Any( mpImpl->maContainerInfo.mxDialogCont ) );
601 }
602 
603 BasicManager::BasicManager( StarBASIC* pSLib, OUString const * pLibPath, bool bDocMgr ) : mbDocMgr( bDocMgr )
604 {
605     Init();
606     DBG_ASSERT( pSLib, "BasicManager cannot be created with a NULL-Pointer!" );
607 
608     if( pLibPath )
609     {
610         mpImpl->aBasicLibPath = *pLibPath;
611     }
612     BasicLibInfo* pStdLibInfo = CreateLibInfo();
613     pStdLibInfo->SetLib( pSLib );
614     StarBASICRef xStdLib = pStdLibInfo->GetLib();
615     xStdLib->SetName(szStdLibName);
616     pStdLibInfo->SetLibName(szStdLibName );
617     pSLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
618 
619     // Save is only necessary if basic has changed
620     xStdLib->SetModified( false );
621 }
622 
623 void BasicManager::ImpMgrNotLoaded( const OUString& rStorageName )
624 {
625     // pErrInf is only destroyed if the error os processed by an
626     // ErrorHandler
627     StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_MGROPEN, rStorageName, DialogMask::ButtonsOk );
628     aErrors.emplace_back(*pErrInf, BasicErrorReason::OPENMGRSTREAM);
629 
630     // Create a stdlib otherwise we crash!
631     BasicLibInfo* pStdLibInfo = CreateLibInfo();
632     pStdLibInfo->SetLib( new StarBASIC( nullptr, mbDocMgr ) );
633     StarBASICRef xStdLib = pStdLibInfo->GetLib();
634     xStdLib->SetName( szStdLibName );
635     pStdLibInfo->SetLibName( szStdLibName );
636     xStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
637     xStdLib->SetModified( false );
638 }
639 
640 
641 void BasicManager::ImpCreateStdLib( StarBASIC* pParentFromStdLib )
642 {
643     BasicLibInfo* pStdLibInfo = CreateLibInfo();
644     StarBASIC* pStdLib = new StarBASIC( pParentFromStdLib, mbDocMgr );
645     pStdLibInfo->SetLib( pStdLib );
646     pStdLib->SetName( szStdLibName );
647     pStdLibInfo->SetLibName( szStdLibName );
648     pStdLib->SetFlag( SbxFlagBits::DontStore | SbxFlagBits::ExtSearch );
649 }
650 
651 void BasicManager::LoadBasicManager( SotStorage& rStorage, const OUString& rBaseURL )
652 {
653     tools::SvRef<SotStorageStream> xManagerStream = rStorage.OpenSotStream( szManagerStream, eStreamReadMode );
654 
655     OUString aStorName( rStorage.GetName() );
656     // #i13114 removed, DBG_ASSERT( aStorName.Len(), "No Storage Name!" );
657 
658     if ( !xManagerStream.is() || xManagerStream->GetError() || ( xManagerStream->TellEnd() == 0 ) )
659     {
660         ImpMgrNotLoaded( aStorName );
661         return;
662     }
663 
664     maStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
665     // #i13114 removed, DBG_ASSERT(aStorageName.Len() != 0, "Bad storage name");
666 
667     OUString aRealStorageName = maStorageName;  // for relative paths, can be modified through BaseURL
668 
669     if ( !rBaseURL.isEmpty() )
670     {
671         INetURLObject aObj( rBaseURL );
672         if ( aObj.GetProtocol() == INetProtocol::File )
673         {
674             aRealStorageName = aObj.PathToFileName();
675         }
676     }
677 
678     xManagerStream->SetBufferSize( 1024 );
679     xManagerStream->Seek( STREAM_SEEK_TO_BEGIN );
680 
681     sal_uInt32 nEndPos;
682     xManagerStream->ReadUInt32( nEndPos );
683 
684     sal_uInt16 nLibs;
685     xManagerStream->ReadUInt16( nLibs );
686     // Plausibility!
687     if( nLibs & 0xF000 )
688     {
689         SAL_WARN( "basic", "BasicManager-Stream defect!" );
690         return;
691     }
692     const size_t nMinBasicLibSize(8);
693     const size_t nMaxPossibleLibs = xManagerStream->remainingSize() / nMinBasicLibSize;
694     if (nLibs > nMaxPossibleLibs)
695     {
696         SAL_WARN("basic", "Parsing error: " << nMaxPossibleLibs <<
697                  " max possible entries, but " << nLibs << " claimed, truncating");
698         nLibs = nMaxPossibleLibs;
699     }
700     for (sal_uInt16 nL = 0; nL < nLibs; ++nL)
701     {
702         BasicLibInfo* pInfo = BasicLibInfo::Create( *xManagerStream );
703 
704         // Correct absolute pathname if relative is existing.
705         // Always try relative first if there are two stands on disk
706         if ( !pInfo->GetRelStorageName().isEmpty() && pInfo->GetRelStorageName() != szImbedded )
707         {
708             INetURLObject aObj( aRealStorageName, INetProtocol::File );
709             aObj.removeSegment();
710             bool bWasAbsolute = false;
711             aObj = aObj.smartRel2Abs( pInfo->GetRelStorageName(), bWasAbsolute );
712 
713             //*** TODO: Replace if still necessary
714             //*** TODO-End
715             if ( ! mpImpl->aBasicLibPath.isEmpty() )
716             {
717                 // Search lib in path
718                 OUString aSearchFile = pInfo->GetRelStorageName();
719                 OUString aSearchFileOldFormat(aSearchFile);
720                 SvtPathOptions aPathCFG;
721                 if( aPathCFG.SearchFile( aSearchFileOldFormat, SvtPathOptions::PATH_BASIC ) )
722                 {
723                     pInfo->SetStorageName( aSearchFile );
724                 }
725             }
726         }
727 
728         mpImpl->aLibs.push_back(std::unique_ptr<BasicLibInfo>(pInfo));
729         // Libs from external files should be loaded only when necessary.
730         // But references are loaded at once, otherwise some big customers get into trouble
731         if ( pInfo->DoLoad() &&
732             ( !pInfo->IsExtern() ||  pInfo->IsReference()))
733         {
734             ImpLoadLibrary( pInfo, &rStorage );
735         }
736     }
737 
738     xManagerStream->Seek( nEndPos );
739     xManagerStream->SetBufferSize( 0 );
740     xManagerStream.clear();
741 }
742 
743 void BasicManager::LoadOldBasicManager( SotStorage& rStorage )
744 {
745     tools::SvRef<SotStorageStream> xManagerStream = rStorage.OpenSotStream( szOldManagerStream, eStreamReadMode );
746 
747     OUString aStorName( rStorage.GetName() );
748     DBG_ASSERT( aStorName.getLength(), "No Storage Name!" );
749 
750     if ( !xManagerStream.is() || xManagerStream->GetError() || ( xManagerStream->TellEnd() == 0 ) )
751     {
752         ImpMgrNotLoaded( aStorName );
753         return;
754     }
755 
756     xManagerStream->SetBufferSize( 1024 );
757     xManagerStream->Seek( STREAM_SEEK_TO_BEGIN );
758     sal_uInt32 nBasicStartOff, nBasicEndOff;
759     xManagerStream->ReadUInt32( nBasicStartOff );
760     xManagerStream->ReadUInt32( nBasicEndOff );
761 
762     DBG_ASSERT( !xManagerStream->GetError(), "Invalid Manager-Stream!" );
763 
764     xManagerStream->Seek( nBasicStartOff );
765     if (!ImplLoadBasic( *xManagerStream, mpImpl->aLibs.front()->GetLibRef() ))
766     {
767         StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_MGROPEN, aStorName, DialogMask::ButtonsOk );
768         aErrors.emplace_back(*pErrInf, BasicErrorReason::OPENMGRSTREAM);
769         // and it proceeds ...
770     }
771     xManagerStream->Seek( nBasicEndOff+1 ); // +1: 0x00 as separator
772     OUString aLibs = xManagerStream->ReadUniOrByteString(xManagerStream->GetStreamCharSet());
773     xManagerStream->SetBufferSize( 0 );
774     xManagerStream.clear(); // Close stream
775 
776     if ( !aLibs.isEmpty() )
777     {
778         INetURLObject aCurStorage( aStorName, INetProtocol::File );
779         sal_Int32 nLibPos {0};
780         do {
781             const OUString aLibInfo(aLibs.getToken(0, LIB_SEP, nLibPos));
782             sal_Int32 nInfoPos {0};
783             const OUString aLibName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
784             DBG_ASSERT( nInfoPos >= 0, "Invalid Lib-Info!" );
785             const OUString aLibAbsStorageName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
786             // TODO: fail also here if there are no more tokens?
787             const OUString aLibRelStorageName( aLibInfo.getToken( 0, LIBINFO_SEP, nInfoPos ) );
788             DBG_ASSERT( nInfoPos < 0, "Invalid Lib-Info!" );
789             INetURLObject aLibAbsStorage( aLibAbsStorageName, INetProtocol::File );
790 
791             INetURLObject aLibRelStorage( aStorName );
792             aLibRelStorage.removeSegment();
793             bool bWasAbsolute = false;
794             aLibRelStorage = aLibRelStorage.smartRel2Abs( aLibRelStorageName, bWasAbsolute);
795             DBG_ASSERT(!bWasAbsolute, "RelStorageName was absolute!" );
796 
797             tools::SvRef<SotStorage> xStorageRef;
798             if ( aLibAbsStorage == aCurStorage || aLibRelStorageName == szImbedded )
799             {
800                 xStorageRef = &rStorage;
801             }
802             else
803             {
804                 xStorageRef = new SotStorage( false, aLibAbsStorage.GetMainURL
805                     ( INetURLObject::DecodeMechanism::NONE ), eStorageReadMode );
806                 if ( xStorageRef->GetError() != ERRCODE_NONE )
807                     xStorageRef = new SotStorage( false, aLibRelStorage.
808                     GetMainURL( INetURLObject::DecodeMechanism::NONE ), eStorageReadMode );
809             }
810             if ( xStorageRef.is() )
811             {
812                 AddLib( *xStorageRef, aLibName, false );
813             }
814             else
815             {
816                 StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_LIBLOAD, aStorName, DialogMask::ButtonsOk );
817                 aErrors.emplace_back(*pErrInf, BasicErrorReason::STORAGENOTFOUND);
818             }
819         } while (nLibPos>=0);
820     }
821 }
822 
823 BasicManager::~BasicManager()
824 {
825     // Notify listener if something needs to be saved
826     Broadcast( SfxHint( SfxHintId::Dying) );
827 }
828 
829 bool BasicManager::HasExeCode( const OUString& sLib )
830 {
831     StarBASIC* pLib = GetLib(sLib);
832     if ( pLib )
833     {
834         for (const auto& pModule: pLib->GetModules())
835         {
836             if (pModule->HasExeCode())
837                 return true;
838         }
839     }
840     return false;
841 }
842 
843 void BasicManager::Init()
844 {
845     mpImpl.reset( new BasicManagerImpl );
846 }
847 
848 BasicLibInfo* BasicManager::CreateLibInfo()
849 {
850     BasicLibInfo* pInf(new BasicLibInfo);
851     mpImpl->aLibs.push_back(std::unique_ptr<BasicLibInfo>(pInf));
852     return pInf;
853 }
854 
855 bool BasicManager::ImpLoadLibrary( BasicLibInfo* pLibInfo, SotStorage* pCurStorage )
856 {
857     try {
858     DBG_ASSERT( pLibInfo, "LibInfo!?" );
859 
860     OUString aStorageName( pLibInfo->GetStorageName() );
861     if ( aStorageName.isEmpty() || aStorageName == szImbedded )
862     {
863         aStorageName = GetStorageName();
864     }
865     tools::SvRef<SotStorage> xStorage;
866     // The current must not be opened again...
867     if ( pCurStorage )
868     {
869         OUString aStorName( pCurStorage->GetName() );
870         // #i13114 removed, DBG_ASSERT( aStorName.Len(), "No Storage Name!" );
871 
872         INetURLObject aCurStorageEntry(aStorName, INetProtocol::File);
873         // #i13114 removed, DBG_ASSERT(aCurStorageEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ).Len() != 0, "Bad storage name");
874 
875         INetURLObject aStorageEntry(aStorageName, INetProtocol::File);
876         // #i13114 removed, DBG_ASSERT(aCurStorageEntry.GetMainURL( INetURLObject::DecodeMechanism::NONE ).Len() != 0, "Bad storage name");
877 
878         if ( aCurStorageEntry == aStorageEntry )
879         {
880             xStorage = pCurStorage;
881         }
882     }
883 
884     if ( !xStorage.is() )
885     {
886         xStorage = new SotStorage( false, aStorageName, eStorageReadMode );
887     }
888     tools::SvRef<SotStorage> xBasicStorage = xStorage->OpenSotStorage( szBasicStorage, eStorageReadMode, false );
889 
890     if ( !xBasicStorage.is() || xBasicStorage->GetError() )
891     {
892         StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_MGROPEN, xStorage->GetName(), DialogMask::ButtonsOk );
893         aErrors.emplace_back(*pErrInf, BasicErrorReason::OPENLIBSTORAGE);
894     }
895     else
896     {
897         // In the Basic-Storage every lib is in a Stream...
898         tools::SvRef<SotStorageStream> xBasicStream = xBasicStorage->OpenSotStream( pLibInfo->GetLibName(), eStreamReadMode );
899         if ( !xBasicStream.is() || xBasicStream->GetError() )
900         {
901             StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_LIBLOAD , pLibInfo->GetLibName(), DialogMask::ButtonsOk );
902             aErrors.emplace_back(*pErrInf, BasicErrorReason::OPENLIBSTREAM);
903         }
904         else
905         {
906             bool bLoaded = false;
907             if ( xBasicStream->TellEnd() != 0 )
908             {
909                 if ( !pLibInfo->GetLib().is() )
910                 {
911                     pLibInfo->SetLib( new StarBASIC( GetStdLib(), mbDocMgr ) );
912                 }
913                 xBasicStream->SetBufferSize( 1024 );
914                 xBasicStream->Seek( STREAM_SEEK_TO_BEGIN );
915                 bLoaded = ImplLoadBasic( *xBasicStream, pLibInfo->GetLibRef() );
916                 xBasicStream->SetBufferSize( 0 );
917                 StarBASICRef xStdLib = pLibInfo->GetLib();
918                 xStdLib->SetName( pLibInfo->GetLibName() );
919                 xStdLib->SetModified( false );
920                 xStdLib->SetFlag( SbxFlagBits::DontStore );
921             }
922             if ( !bLoaded )
923             {
924                 StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_LIBLOAD, pLibInfo->GetLibName(), DialogMask::ButtonsOk );
925                 aErrors.emplace_back(*pErrInf, BasicErrorReason::BASICLOADERROR);
926             }
927             else
928             {
929                 // Perhaps there are additional information in the stream...
930                 xBasicStream->SetCryptMaskKey(szCryptingKey);
931                 xBasicStream->RefreshBuffer();
932                 sal_uInt32 nPasswordMarker = 0;
933                 xBasicStream->ReadUInt32( nPasswordMarker );
934                 if ( ( nPasswordMarker == PASSWORD_MARKER ) && !xBasicStream->eof() )
935                 {
936                     OUString aPassword = xBasicStream->ReadUniOrByteString(
937                         xBasicStream->GetStreamCharSet());
938                     pLibInfo->SetPassword( aPassword );
939                 }
940                 xBasicStream->SetCryptMaskKey(OString());
941                 CheckModules( pLibInfo->GetLib().get(), pLibInfo->IsReference() );
942             }
943             return bLoaded;
944         }
945     }
946     }
947     catch (const css::ucb::ContentCreationException&)
948     {
949     }
950     return false;
951 }
952 
953 bool BasicManager::ImplEncryptStream( SvStream& rStrm )
954 {
955     sal_uInt64 const nPos = rStrm.Tell();
956     sal_uInt32 nCreator;
957     rStrm.ReadUInt32( nCreator );
958     rStrm.Seek( nPos );
959     bool bProtected = false;
960     if ( nCreator != SBXCR_SBX )
961     {
962         // Should only be the case for encrypted Streams
963         bProtected = true;
964         rStrm.SetCryptMaskKey(szCryptingKey);
965         rStrm.RefreshBuffer();
966     }
967     return bProtected;
968 }
969 
970 // This code is necessary to load the BASIC of Beta 1
971 // TODO: Which Beta 1?
972 bool BasicManager::ImplLoadBasic( SvStream& rStrm, StarBASICRef& rOldBasic ) const
973 {
974     bool bProtected = ImplEncryptStream( rStrm );
975     SbxBaseRef xNew = SbxBase::Load( rStrm );
976     bool bLoaded = false;
977     if( xNew.is() )
978     {
979         if( auto pNew = dynamic_cast<StarBASIC*>( xNew.get() ) )
980         {
981             // Use the Parent of the old BASICs
982             if( rOldBasic.is() )
983             {
984                 pNew->SetParent( rOldBasic->GetParent() );
985                 if( pNew->GetParent() )
986                 {
987                     pNew->GetParent()->Insert( pNew );
988                 }
989                 pNew->SetFlag( SbxFlagBits::ExtSearch );
990             }
991             rOldBasic = pNew;
992 
993             // Fill new library container (5.2 -> 6.0)
994             copyToLibraryContainer( pNew, mpImpl->maContainerInfo );
995 
996             pNew->SetModified( false );
997             bLoaded = true;
998         }
999     }
1000     if ( bProtected )
1001     {
1002         rStrm.SetCryptMaskKey(OString());
1003     }
1004     return bLoaded;
1005 }
1006 
1007 void BasicManager::CheckModules( StarBASIC* pLib, bool bReference )
1008 {
1009     if ( !pLib )
1010     {
1011         return;
1012     }
1013     bool bModified = pLib->IsModified();
1014 
1015     for ( const auto& pModule: pLib->GetModules() )
1016     {
1017         DBG_ASSERT(pModule, "Module not received!");
1018         if ( !pModule->IsCompiled() && !StarBASIC::GetErrorCode() )
1019         {
1020             pModule->Compile();
1021         }
1022     }
1023 
1024     // #67477, AB 8.12.99 On demand compile in referenced libs should not
1025     // cause modified
1026     if( !bModified && bReference )
1027     {
1028         OSL_FAIL( "Referenced basic library is not compiled!" );
1029         pLib->SetModified( false );
1030     }
1031 }
1032 
1033 StarBASIC* BasicManager::AddLib( SotStorage& rStorage, const OUString& rLibName, bool bReference )
1034 {
1035     OUString aStorName( rStorage.GetName() );
1036     DBG_ASSERT( !aStorName.isEmpty(), "No Storage Name!" );
1037 
1038     OUString aStorageName = INetURLObject(aStorName, INetProtocol::File).GetMainURL( INetURLObject::DecodeMechanism::NONE );
1039     DBG_ASSERT(!aStorageName.isEmpty(), "Bad storage name");
1040 
1041     OUString aNewLibName( rLibName );
1042     while ( HasLib( aNewLibName ) )
1043     {
1044         aNewLibName += "_";
1045     }
1046     BasicLibInfo* pLibInfo = CreateLibInfo();
1047     // Use original name otherwise ImpLoadLibrary fails...
1048     pLibInfo->SetLibName( rLibName );
1049     // but doesn't work this way if name exists twice
1050     sal_uInt16 nLibId = static_cast<sal_uInt16>(mpImpl->aLibs.size()) - 1;
1051 
1052     // Set StorageName before load because it is compared with pCurStorage
1053     pLibInfo->SetStorageName( aStorageName );
1054     bool bLoaded = ImpLoadLibrary( pLibInfo, &rStorage );
1055 
1056     if ( bLoaded )
1057     {
1058         if ( aNewLibName != rLibName )
1059         {
1060             pLibInfo->SetLibName(aNewLibName);
1061         }
1062         if ( bReference )
1063         {
1064             pLibInfo->GetLib()->SetModified( false );   // Don't save in this case
1065             pLibInfo->SetRelStorageName( OUString() );
1066             pLibInfo->SetReference(true);
1067         }
1068         else
1069         {
1070             pLibInfo->GetLib()->SetModified( true ); // Must be saved after Add!
1071             pLibInfo->SetStorageName( szImbedded ); // Save in BasicManager-Storage
1072         }
1073     }
1074     else
1075     {
1076         RemoveLib( nLibId, false );
1077         pLibInfo = nullptr;
1078     }
1079 
1080     return pLibInfo ? &*pLibInfo->GetLib() : nullptr;
1081 
1082 }
1083 
1084 bool BasicManager::IsReference( sal_uInt16 nLib )
1085 {
1086     DBG_ASSERT( nLib < mpImpl->aLibs.size(), "Lib does not exist!" );
1087     if ( nLib < mpImpl->aLibs.size() )
1088     {
1089         return mpImpl->aLibs[nLib]->IsReference();
1090     }
1091     return false;
1092 }
1093 
1094 void BasicManager::RemoveLib( sal_uInt16 nLib )
1095 {
1096     // Only physical deletion if no reference
1097     RemoveLib( nLib, !IsReference( nLib ) );
1098 }
1099 
1100 bool BasicManager::RemoveLib( sal_uInt16 nLib, bool bDelBasicFromStorage )
1101 {
1102     DBG_ASSERT( nLib, "Standard-Lib cannot be removed!" );
1103 
1104     DBG_ASSERT( !nLib || nLib  < mpImpl->aLibs.size(), "Lib not found!" );
1105 
1106     if( !nLib || nLib  < mpImpl->aLibs.size() )
1107     {
1108         StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_REMOVELIB, OUString(), DialogMask::ButtonsOk );
1109         aErrors.emplace_back(*pErrInf, BasicErrorReason::STDLIB);
1110         return false;
1111     }
1112 
1113     auto const itLibInfo = mpImpl->aLibs.begin() + nLib;
1114 
1115     // If one of the streams cannot be opened, this is not an error,
1116     // because BASIC was never written before...
1117     if (bDelBasicFromStorage && !(*itLibInfo)->IsReference() &&
1118            (!(*itLibInfo)->IsExtern() || SotStorage::IsStorageFile((*itLibInfo)->GetStorageName())))
1119     {
1120         tools::SvRef<SotStorage> xStorage;
1121         try
1122         {
1123             if (!(*itLibInfo)->IsExtern())
1124             {
1125                 xStorage = new SotStorage(false, GetStorageName());
1126             }
1127             else
1128             {
1129                 xStorage = new SotStorage(false, (*itLibInfo)->GetStorageName());
1130             }
1131         }
1132         catch (const css::ucb::ContentCreationException& e)
1133         {
1134             SAL_WARN("basic", "BasicManager::RemoveLib: " << e);
1135         }
1136 
1137         if (xStorage.is() && xStorage->IsStorage(szBasicStorage))
1138         {
1139             tools::SvRef<SotStorage> xBasicStorage = xStorage->OpenSotStorage
1140                             ( szBasicStorage, StreamMode::STD_READWRITE, false );
1141 
1142             if ( !xBasicStorage.is() || xBasicStorage->GetError() )
1143             {
1144                 StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_REMOVELIB, OUString(), DialogMask::ButtonsOk );
1145                 aErrors.emplace_back(*pErrInf, BasicErrorReason::OPENLIBSTORAGE);
1146             }
1147             else if (xBasicStorage->IsStream((*itLibInfo)->GetLibName()))
1148             {
1149                 xBasicStorage->Remove((*itLibInfo)->GetLibName());
1150                 xBasicStorage->Commit();
1151 
1152                 // If no further stream available,
1153                 // delete the SubStorage.
1154                 SvStorageInfoList aInfoList;
1155                 xBasicStorage->FillInfoList( &aInfoList );
1156                 if ( aInfoList.empty() )
1157                 {
1158                     xBasicStorage.clear();
1159                     xStorage->Remove( szBasicStorage );
1160                     xStorage->Commit();
1161                     // If no further Streams or SubStorages available,
1162                     // delete the Storage, too.
1163                     aInfoList.clear();
1164                     xStorage->FillInfoList( &aInfoList );
1165                     if ( aInfoList.empty() )
1166                     {
1167                         //OUString aName_( xStorage->GetName() );
1168                         xStorage.clear();
1169                         //*** TODO: Replace if still necessary
1170                         //SfxContentHelper::Kill( aName );
1171                         //*** TODO-End
1172                     }
1173                 }
1174             }
1175         }
1176     }
1177     if ((*itLibInfo)->GetLib().is())
1178     {
1179         GetStdLib()->Remove( (*itLibInfo)->GetLib().get() );
1180     }
1181     mpImpl->aLibs.erase(itLibInfo);
1182     return true;    // Remove was successful, del unimportant
1183 }
1184 
1185 sal_uInt16 BasicManager::GetLibCount() const
1186 {
1187     return static_cast<sal_uInt16>(mpImpl->aLibs.size());
1188 }
1189 
1190 StarBASIC* BasicManager::GetLib( sal_uInt16 nLib ) const
1191 {
1192     DBG_ASSERT( nLib < mpImpl->aLibs.size(), "Lib does not exist!" );
1193     if ( nLib < mpImpl->aLibs.size() )
1194     {
1195         return mpImpl->aLibs[nLib]->GetLib().get();
1196     }
1197     return nullptr;
1198 }
1199 
1200 StarBASIC* BasicManager::GetStdLib() const
1201 {
1202     StarBASIC* pLib = GetLib( 0 );
1203     return pLib;
1204 }
1205 
1206 StarBASIC* BasicManager::GetLib( const OUString& rName ) const
1207 {
1208     for (auto const& rpLib : mpImpl->aLibs)
1209     {
1210         if (rpLib->GetLibName().equalsIgnoreAsciiCase(rName)) // Check if available...
1211         {
1212             return rpLib->GetLib().get();
1213         }
1214     }
1215     return nullptr;
1216 }
1217 
1218 sal_uInt16 BasicManager::GetLibId( const OUString& rName ) const
1219 {
1220     for (size_t i = 0; i < mpImpl->aLibs.size(); i++)
1221     {
1222         if (mpImpl->aLibs[i]->GetLibName().equalsIgnoreAsciiCase( rName ))
1223         {
1224             return static_cast<sal_uInt16>(i);
1225         }
1226     }
1227     return LIB_NOTFOUND;
1228 }
1229 
1230 bool BasicManager::HasLib( const OUString& rName ) const
1231 {
1232     for (const auto& rpLib : mpImpl->aLibs)
1233     {
1234         if (rpLib->GetLibName().equalsIgnoreAsciiCase(rName)) // Check if available...
1235         {
1236             return true;
1237         }
1238     }
1239     return false;
1240 }
1241 
1242 OUString BasicManager::GetLibName( sal_uInt16 nLib )
1243 {
1244     DBG_ASSERT(  nLib < mpImpl->aLibs.size(), "Lib?!" );
1245     if ( nLib < mpImpl->aLibs.size() )
1246     {
1247         return mpImpl->aLibs[nLib]->GetLibName();
1248     }
1249     return OUString();
1250 }
1251 
1252 bool BasicManager::LoadLib( sal_uInt16 nLib )
1253 {
1254     bool bDone = false;
1255     DBG_ASSERT( nLib < mpImpl->aLibs.size() , "Lib?!" );
1256     if ( nLib < mpImpl->aLibs.size() )
1257     {
1258         BasicLibInfo& rLibInfo = *mpImpl->aLibs[nLib];
1259         uno::Reference< script::XLibraryContainer > xLibContainer = rLibInfo.GetLibraryContainer();
1260         if( xLibContainer.is() )
1261         {
1262             OUString aLibName = rLibInfo.GetLibName();
1263             xLibContainer->loadLibrary( aLibName );
1264             bDone = xLibContainer->isLibraryLoaded( aLibName );
1265         }
1266         else
1267         {
1268             bDone = ImpLoadLibrary( &rLibInfo, nullptr );
1269             StarBASIC* pLib = GetLib( nLib );
1270             if ( pLib )
1271             {
1272                 GetStdLib()->Insert( pLib );
1273                 pLib->SetFlag( SbxFlagBits::ExtSearch );
1274             }
1275         }
1276     }
1277     else
1278     {
1279         StringErrorInfo* pErrInf = new StringErrorInfo( ERRCODE_BASMGR_LIBLOAD, OUString(), DialogMask::ButtonsOk );
1280         aErrors.emplace_back(*pErrInf, BasicErrorReason::LIBNOTFOUND);
1281     }
1282     return bDone;
1283 }
1284 
1285 StarBASIC* BasicManager::CreateLib( const OUString& rLibName )
1286 {
1287     if ( GetLib( rLibName ) )
1288     {
1289         return nullptr;
1290     }
1291     BasicLibInfo* pLibInfo = CreateLibInfo();
1292     StarBASIC* pNew = new StarBASIC( GetStdLib(), mbDocMgr );
1293     GetStdLib()->Insert( pNew );
1294     pNew->SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::DontStore );
1295     pLibInfo->SetLib( pNew );
1296     pLibInfo->SetLibName( rLibName );
1297     pLibInfo->GetLib()->SetName( rLibName );
1298     return pLibInfo->GetLib().get();
1299 }
1300 
1301 // For XML import/export:
1302 StarBASIC* BasicManager::CreateLib( const OUString& rLibName, const OUString& Password,
1303                                     const OUString& LinkTargetURL )
1304 {
1305     // Ask if lib exists because standard lib is always there
1306     StarBASIC* pLib = GetLib( rLibName );
1307     if( !pLib )
1308     {
1309         if( !LinkTargetURL.isEmpty())
1310         {
1311             try
1312             {
1313                 tools::SvRef<SotStorage> xStorage = new SotStorage(false, LinkTargetURL, StreamMode::READ | StreamMode::SHARE_DENYWRITE);
1314                 if (!xStorage->GetError())
1315                 {
1316                     pLib = AddLib(*xStorage, rLibName, true);
1317                 }
1318             }
1319             catch (const css::ucb::ContentCreationException& e)
1320             {
1321                 SAL_WARN("basic", "BasicManager::RemoveLib: " << e);
1322             }
1323             DBG_ASSERT( pLib, "XML Import: Linked basic library could not be loaded");
1324         }
1325         else
1326         {
1327             pLib = CreateLib( rLibName );
1328             if( Password.isEmpty())
1329             {
1330                 BasicLibInfo* pLibInfo = FindLibInfo( pLib );
1331                 pLibInfo ->SetPassword( Password );
1332             }
1333         }
1334         //ExternalSourceURL ?
1335     }
1336     return pLib;
1337 }
1338 
1339 StarBASIC* BasicManager::CreateLibForLibContainer( const OUString& rLibName,
1340     const uno::Reference< script::XLibraryContainer >& xScriptCont )
1341 {
1342     if ( GetLib( rLibName ) )
1343     {
1344         return nullptr;
1345     }
1346     BasicLibInfo* pLibInfo = CreateLibInfo();
1347     StarBASIC* pNew = new StarBASIC( GetStdLib(), mbDocMgr );
1348     GetStdLib()->Insert( pNew );
1349     pNew->SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::DontStore );
1350     pLibInfo->SetLib( pNew );
1351     pLibInfo->SetLibName( rLibName );
1352     pLibInfo->GetLib()->SetName( rLibName );
1353     pLibInfo->SetLibraryContainer( xScriptCont );
1354     return pNew;
1355 }
1356 
1357 
1358 BasicLibInfo* BasicManager::FindLibInfo( StarBASIC const * pBasic )
1359 {
1360     for (auto const& rpLib : mpImpl->aLibs)
1361     {
1362         if (rpLib->GetLib().get() == pBasic)
1363         {
1364             return rpLib.get();
1365         }
1366     }
1367     return nullptr;
1368 }
1369 
1370 
1371 bool BasicManager::IsBasicModified() const
1372 {
1373     for (auto const& rpLib : mpImpl->aLibs)
1374     {
1375         if (rpLib->GetLib().is() && rpLib->GetLib()->IsModified())
1376         {
1377             return true;
1378         }
1379     }
1380     return false;
1381 }
1382 
1383 
1384 bool BasicManager::GetGlobalUNOConstant( const OUString& rName, uno::Any& aOut )
1385 {
1386     bool bRes = false;
1387     StarBASIC* pStandardLib = GetStdLib();
1388     OSL_PRECOND( pStandardLib, "BasicManager::GetGlobalUNOConstant: no lib to read from!" );
1389     if ( pStandardLib )
1390         bRes = pStandardLib->GetUNOConstant( rName, aOut );
1391     return bRes;
1392 }
1393 
1394 uno::Any BasicManager::SetGlobalUNOConstant( const OUString& rName, const uno::Any& _rValue )
1395 {
1396     uno::Any aOldValue;
1397 
1398     StarBASIC* pStandardLib = GetStdLib();
1399     OSL_PRECOND( pStandardLib, "BasicManager::SetGlobalUNOConstant: no lib to insert into!" );
1400     if ( !pStandardLib )
1401         return aOldValue;
1402 
1403     // obtain the old value
1404     SbxVariable* pVariable = pStandardLib->Find( rName, SbxClassType::Object );
1405     if ( pVariable )
1406         aOldValue = sbxToUnoValue( pVariable );
1407 
1408     SbxObjectRef xUnoObj = GetSbUnoObject( rName, _rValue );
1409     xUnoObj->SetFlag( SbxFlagBits::DontStore );
1410     pStandardLib->Insert( xUnoObj.get() );
1411 
1412     return aOldValue;
1413 }
1414 
1415 bool BasicManager::LegacyPsswdBinaryLimitExceeded( std::vector< OUString >& _out_rModuleNames )
1416 {
1417     try
1418     {
1419         uno::Reference< container::XNameAccess > xScripts( GetScriptLibraryContainer(), uno::UNO_QUERY_THROW );
1420         uno::Reference< script::XLibraryContainerPassword > xPassword( GetScriptLibraryContainer(), uno::UNO_QUERY_THROW );
1421 
1422         uno::Sequence< OUString > aNames( xScripts->getElementNames() );
1423         for ( auto const & scriptElementName : aNames )
1424         {
1425             if( !xPassword->isLibraryPasswordProtected( scriptElementName ) )
1426                 continue;
1427 
1428             StarBASIC* pBasicLib = GetLib( scriptElementName );
1429             if ( !pBasicLib )
1430                 continue;
1431 
1432             uno::Reference< container::XNameAccess > xScriptLibrary( xScripts->getByName( scriptElementName ), uno::UNO_QUERY_THROW );
1433             uno::Sequence< OUString > aElementNames( xScriptLibrary->getElementNames() );
1434             sal_Int32 nLen = aElementNames.getLength();
1435 
1436             std::vector< OUString > aBigModules( nLen );
1437             sal_Int32 nBigModules = 0;
1438 
1439             for ( auto const & libraryElementName : aElementNames )
1440             {
1441                 SbModule* pMod = pBasicLib->FindModule( libraryElementName );
1442                 if ( pMod && pMod->ExceedsLegacyModuleSize() )
1443                     aBigModules[ nBigModules++ ] = libraryElementName;
1444             }
1445 
1446             if ( nBigModules )
1447             {
1448                 _out_rModuleNames.swap(aBigModules);
1449                 return true;
1450             }
1451         }
1452     }
1453     catch( const uno::Exception& )
1454     {
1455         DBG_UNHANDLED_EXCEPTION("basic");
1456     }
1457     return false;
1458 }
1459 
1460 
1461 namespace
1462 {
1463     SbMethod* lcl_queryMacro( BasicManager* i_manager, OUString const& i_fullyQualifiedName )
1464     {
1465         sal_Int32 nLast = 0;
1466         const OUString sLibName {i_fullyQualifiedName.getToken( 0, '.', nLast )};
1467         const OUString sModule {i_fullyQualifiedName.getToken( 0, '.', nLast )};
1468         OUString sMacro;
1469         if(nLast >= 0)
1470         {
1471             sMacro = i_fullyQualifiedName.copy(nLast);
1472         }
1473         else
1474         {
1475             sMacro = i_fullyQualifiedName;
1476         }
1477 
1478         utl::TransliterationWrapper& rTransliteration = SbGlobal::GetTransliteration();
1479         sal_uInt16 nLibCount = i_manager->GetLibCount();
1480         for ( sal_uInt16 nLib = 0; nLib < nLibCount; ++nLib )
1481         {
1482             if ( rTransliteration.isEqual( i_manager->GetLibName( nLib ), sLibName ) )
1483             {
1484                 StarBASIC* pLib = i_manager->GetLib( nLib );
1485                 if( !pLib )
1486                 {
1487                     bool const bLoaded = i_manager->LoadLib( nLib );
1488                     if (bLoaded)
1489                     {
1490                         pLib = i_manager->GetLib( nLib );
1491                     }
1492                 }
1493 
1494                 if( pLib )
1495                 {
1496                     for ( const auto& pMod: pLib->GetModules() )
1497                     {
1498                         if ( rTransliteration.isEqual( pMod->GetName(), sModule ) )
1499                         {
1500                             SbMethod* pMethod = static_cast<SbMethod*>(pMod->Find( sMacro, SbxClassType::Method ));
1501                             if( pMethod )
1502                             {
1503                                 return pMethod;
1504                             }
1505                         }
1506                     }
1507                 }
1508             }
1509         }
1510         return nullptr;
1511     }
1512 }
1513 
1514 bool BasicManager::HasMacro( OUString const& i_fullyQualifiedName ) const
1515 {
1516     return ( lcl_queryMacro( const_cast< BasicManager* >( this ), i_fullyQualifiedName ) != nullptr );
1517 }
1518 
1519 ErrCode BasicManager::ExecuteMacro( OUString const& i_fullyQualifiedName, SbxArray* i_arguments, SbxValue* i_retValue )
1520 {
1521     SbMethod* pMethod = lcl_queryMacro( this, i_fullyQualifiedName );
1522     ErrCode nError = ERRCODE_NONE;
1523     if ( pMethod )
1524     {
1525         if ( i_arguments )
1526             pMethod->SetParameters( i_arguments );
1527         nError = pMethod->Call( i_retValue );
1528     }
1529     else
1530         nError = ERRCODE_BASIC_PROC_UNDEFINED;
1531     return nError;
1532 }
1533 
1534 ErrCode BasicManager::ExecuteMacro( OUString const& i_fullyQualifiedName, OUString const& i_commaSeparatedArgs, SbxValue* i_retValue )
1535 {
1536     SbMethod* pMethod = lcl_queryMacro( this, i_fullyQualifiedName );
1537     if ( !pMethod )
1538     {
1539         return ERRCODE_BASIC_PROC_UNDEFINED;
1540     }
1541     // arguments must be quoted
1542     OUString sQuotedArgs;
1543     OUStringBuffer sArgs( i_commaSeparatedArgs );
1544     if ( sArgs.getLength()<2 || sArgs[1] == '\"')
1545     {
1546         // no args or already quoted args
1547         sQuotedArgs = sArgs.makeStringAndClear();
1548     }
1549     else
1550     {
1551         // quote parameters
1552         sArgs.remove( 0, 1 );
1553         sArgs.remove( sArgs.getLength() - 1, 1 );
1554 
1555         OUStringBuffer aBuff;
1556         OUString sArgs2 = sArgs.makeStringAndClear();
1557 
1558         aBuff.append("(");
1559         if (!sArgs2.isEmpty())
1560         {
1561 
1562             sal_Int32 nPos {0};
1563             for (;;)
1564             {
1565                 aBuff.append( "\"" );
1566                 aBuff.append( sArgs2.getToken(0, ',', nPos) );
1567                 aBuff.append( "\"" );
1568                 if (nPos<0)
1569                     break;
1570                 aBuff.append( "," );
1571             }
1572         }
1573         aBuff.append( ")" );
1574 
1575         sQuotedArgs = aBuff.makeStringAndClear();
1576     }
1577 
1578     // add quoted arguments and do the call
1579     OUString sCall = "["
1580                    + pMethod->GetName()
1581                    + sQuotedArgs
1582                    + "]";
1583 
1584     SbxVariable* pRet = pMethod->GetParent()->Execute( sCall );
1585     if ( pRet && ( pRet != pMethod ) )
1586     {
1587         *i_retValue = *pRet;
1588     }
1589     return SbxBase::GetError();
1590 }
1591 
1592 
1593 class ModuleInfo_Impl : public ModuleInfoHelper
1594 {
1595     OUString maName;
1596     OUString maLanguage;
1597     OUString maSource;
1598 
1599 public:
1600     ModuleInfo_Impl( const OUString& aName, const OUString& aLanguage, const OUString& aSource )
1601         : maName( aName ), maLanguage( aLanguage), maSource( aSource ) {}
1602 
1603     // Methods XStarBasicModuleInfo
1604     virtual OUString SAL_CALL getName() override
1605         { return maName; }
1606     virtual OUString SAL_CALL getLanguage() override
1607         { return maLanguage; }
1608     virtual OUString SAL_CALL getSource() override
1609         { return maSource; }
1610 };
1611 
1612 
1613 class DialogInfo_Impl : public WeakImplHelper< script::XStarBasicDialogInfo >
1614 {
1615     OUString maName;
1616     uno::Sequence< sal_Int8 > mData;
1617 
1618 public:
1619     DialogInfo_Impl( const OUString& aName, const uno::Sequence< sal_Int8 >& Data )
1620         : maName( aName ), mData( Data ) {}
1621 
1622     // Methods XStarBasicDialogInfo
1623     virtual OUString SAL_CALL getName() override
1624         { return maName; }
1625     virtual uno::Sequence< sal_Int8 > SAL_CALL getData() override
1626         { return mData; }
1627 };
1628 
1629 
1630 class LibraryInfo_Impl : public WeakImplHelper< script::XStarBasicLibraryInfo >
1631 {
1632     OUString maName;
1633     uno::Reference< container::XNameContainer > mxModuleContainer;
1634     uno::Reference< container::XNameContainer > mxDialogContainer;
1635     OUString maPassword;
1636     OUString maExternaleSourceURL;
1637     OUString maLinkTargetURL;
1638 
1639 public:
1640     LibraryInfo_Impl
1641     (
1642         const OUString& aName,
1643         uno::Reference< container::XNameContainer > const & xModuleContainer,
1644         uno::Reference< container::XNameContainer > const & xDialogContainer,
1645         const OUString& aPassword,
1646         const OUString& aExternaleSourceURL,
1647         const OUString& aLinkTargetURL
1648     )
1649         : maName( aName )
1650         , mxModuleContainer( xModuleContainer )
1651         , mxDialogContainer( xDialogContainer )
1652         , maPassword( aPassword )
1653         , maExternaleSourceURL( aExternaleSourceURL )
1654         , maLinkTargetURL( aLinkTargetURL )
1655     {}
1656 
1657     // Methods XStarBasicLibraryInfo
1658     virtual OUString SAL_CALL getName() override
1659         { return maName; }
1660     virtual uno::Reference< container::XNameContainer > SAL_CALL getModuleContainer() override
1661         { return mxModuleContainer; }
1662     virtual uno::Reference< container::XNameContainer > SAL_CALL getDialogContainer() override
1663         { return mxDialogContainer; }
1664     virtual OUString SAL_CALL getPassword() override
1665         { return maPassword; }
1666     virtual OUString SAL_CALL getExternalSourceURL() override
1667         { return maExternaleSourceURL; }
1668     virtual OUString SAL_CALL getLinkTargetURL() override
1669         { return maLinkTargetURL; }
1670 };
1671 
1672 
1673 class ModuleContainer_Impl : public NameContainerHelper
1674 {
1675     StarBASIC* mpLib;
1676 
1677 public:
1678     explicit ModuleContainer_Impl( StarBASIC* pLib )
1679         :mpLib( pLib ) {}
1680 
1681     // Methods XElementAccess
1682     virtual uno::Type SAL_CALL getElementType() override;
1683     virtual sal_Bool SAL_CALL hasElements() override;
1684 
1685     // Methods XNameAccess
1686     virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
1687     virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
1688     virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
1689 
1690     // Methods XNameReplace
1691     virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
1692 
1693     // Methods XNameContainer
1694     virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
1695     virtual void SAL_CALL removeByName( const OUString& Name ) override;
1696 };
1697 
1698 // Methods XElementAccess
1699 uno::Type ModuleContainer_Impl::getElementType()
1700 {
1701     uno::Type aModuleType = cppu::UnoType<script::XStarBasicModuleInfo>::get();
1702     return aModuleType;
1703 }
1704 
1705 sal_Bool ModuleContainer_Impl::hasElements()
1706 {
1707     return mpLib && !mpLib->GetModules().empty();
1708 }
1709 
1710 // Methods XNameAccess
1711 uno::Any ModuleContainer_Impl::getByName( const OUString& aName )
1712 {
1713     SbModule* pMod = mpLib ? mpLib->FindModule( aName ) : nullptr;
1714     if( !pMod )
1715         throw container::NoSuchElementException();
1716     uno::Reference< script::XStarBasicModuleInfo > xMod = new ModuleInfo_Impl( aName, "StarBasic", pMod->GetSource32() );
1717     uno::Any aRetAny;
1718     aRetAny <<= xMod;
1719     return aRetAny;
1720 }
1721 
1722 uno::Sequence< OUString > ModuleContainer_Impl::getElementNames()
1723 {
1724     sal_uInt16 nMods = mpLib ? mpLib->GetModules().size() : 0;
1725     uno::Sequence< OUString > aRetSeq( nMods );
1726     OUString* pRetSeq = aRetSeq.getArray();
1727     for( sal_uInt16 i = 0 ; i < nMods ; i++ )
1728     {
1729         pRetSeq[i] = mpLib->GetModules()[i]->GetName();
1730     }
1731     return aRetSeq;
1732 }
1733 
1734 sal_Bool ModuleContainer_Impl::hasByName( const OUString& aName )
1735 {
1736     SbModule* pMod = mpLib ? mpLib->FindModule( aName ) : nullptr;
1737     bool bRet = (pMod != nullptr);
1738     return bRet;
1739 }
1740 
1741 
1742 // Methods XNameReplace
1743 void ModuleContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
1744 {
1745     removeByName( aName );
1746     insertByName( aName, aElement );
1747 }
1748 
1749 
1750 // Methods XNameContainer
1751 void ModuleContainer_Impl::insertByName( const OUString& aName, const uno::Any& aElement )
1752 {
1753     uno::Type aModuleType = cppu::UnoType<script::XStarBasicModuleInfo>::get();
1754     const uno::Type& aAnyType = aElement.getValueType();
1755     if( aModuleType != aAnyType )
1756     {
1757         throw lang::IllegalArgumentException();
1758     }
1759     uno::Reference< script::XStarBasicModuleInfo > xMod;
1760     aElement >>= xMod;
1761     mpLib->MakeModule( aName, xMod->getSource() );
1762 }
1763 
1764 void ModuleContainer_Impl::removeByName( const OUString& Name )
1765 {
1766     SbModule* pMod = mpLib ? mpLib->FindModule( Name ) : nullptr;
1767     if( !pMod )
1768     {
1769         throw container::NoSuchElementException();
1770     }
1771     mpLib->Remove( pMod );
1772 }
1773 
1774 
1775 static uno::Sequence< sal_Int8 > implGetDialogData( SbxObject* pDialog )
1776 {
1777     SvMemoryStream aMemStream;
1778     pDialog->Store( aMemStream );
1779     sal_Int32 nLen = aMemStream.Tell();
1780     if (nLen < 0) { abort(); }
1781     uno::Sequence< sal_Int8 > aData( nLen );
1782     sal_Int8* pDestData = aData.getArray();
1783     const sal_Int8* pSrcData = static_cast<const sal_Int8*>(aMemStream.GetData());
1784     memcpy( pDestData, pSrcData, nLen );
1785     return aData;
1786 }
1787 
1788 static SbxObject* implCreateDialog( const uno::Sequence< sal_Int8 >& aData )
1789 {
1790     sal_Int8* pData = const_cast< uno::Sequence< sal_Int8 >& >(aData).getArray();
1791     SvMemoryStream aMemStream( pData, aData.getLength(), StreamMode::READ );
1792     SbxBase* pBase = SbxBase::Load( aMemStream );
1793     return dynamic_cast<SbxObject*>(pBase);
1794 }
1795 
1796 // HACK! Because this value is defined in basctl/inc/vcsbxdef.hxx
1797 // which we can't include here, we have to use the value directly
1798 #define SBXID_DIALOG        101
1799 
1800 
1801 class DialogContainer_Impl : public NameContainerHelper
1802 {
1803     StarBASIC* mpLib;
1804 
1805 public:
1806     explicit DialogContainer_Impl( StarBASIC* pLib )
1807         :mpLib( pLib ) {}
1808 
1809     // Methods XElementAccess
1810     virtual uno::Type SAL_CALL getElementType() override;
1811     virtual sal_Bool SAL_CALL hasElements() override;
1812 
1813     // Methods XNameAccess
1814     virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
1815     virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
1816     virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
1817 
1818     // Methods XNameReplace
1819     virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
1820 
1821     // Methods XNameContainer
1822     virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
1823     virtual void SAL_CALL removeByName( const OUString& Name ) override;
1824 };
1825 
1826 // Methods XElementAccess
1827 uno::Type DialogContainer_Impl::getElementType()
1828 {
1829     uno::Type aModuleType = cppu::UnoType<script::XStarBasicDialogInfo>::get();
1830     return aModuleType;
1831 }
1832 
1833 sal_Bool DialogContainer_Impl::hasElements()
1834 {
1835     bool bRet = false;
1836 
1837     sal_Int16 nCount = mpLib->GetObjects()->Count();
1838     for( sal_Int16 nObj = 0; nObj < nCount ; nObj++ )
1839     {
1840         SbxVariable* pVar = mpLib->GetObjects()->Get( nObj );
1841         SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
1842         if ( pObj && (pObj->GetSbxId() == SBXID_DIALOG ) )
1843         {
1844             bRet = true;
1845             break;
1846         }
1847     }
1848     return bRet;
1849 }
1850 
1851 // Methods XNameAccess
1852 uno::Any DialogContainer_Impl::getByName( const OUString& aName )
1853 {
1854     SbxVariable* pVar = mpLib->GetObjects()->Find( aName, SbxClassType::DontCare );
1855     SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
1856     if( !( pObj && pObj->GetSbxId() == SBXID_DIALOG ) )
1857     {
1858         throw container::NoSuchElementException();
1859     }
1860 
1861     uno::Reference< script::XStarBasicDialogInfo > xDialog =
1862         new DialogInfo_Impl(aName, implGetDialogData(pObj));
1863 
1864     uno::Any aRetAny;
1865     aRetAny <<= xDialog;
1866     return aRetAny;
1867 }
1868 
1869 uno::Sequence< OUString > DialogContainer_Impl::getElementNames()
1870 {
1871     sal_Int16 nCount = mpLib->GetObjects()->Count();
1872     uno::Sequence< OUString > aRetSeq( nCount );
1873     OUString* pRetSeq = aRetSeq.getArray();
1874     sal_Int32 nDialogCounter = 0;
1875 
1876     for( sal_Int16 nObj = 0; nObj < nCount ; nObj++ )
1877     {
1878         SbxVariable* pVar = mpLib->GetObjects()->Get( nObj );
1879         SbxObject* pObj = dynamic_cast<SbxObject*> (pVar);
1880         if ( pObj && ( pObj->GetSbxId() == SBXID_DIALOG ) )
1881         {
1882             pRetSeq[ nDialogCounter ] = pVar->GetName();
1883             nDialogCounter++;
1884         }
1885     }
1886     aRetSeq.realloc( nDialogCounter );
1887     return aRetSeq;
1888 }
1889 
1890 sal_Bool DialogContainer_Impl::hasByName( const OUString& aName )
1891 {
1892     bool bRet = false;
1893     SbxVariable* pVar = mpLib->GetObjects()->Find( aName, SbxClassType::DontCare );
1894     SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
1895     if( pObj &&  ( pObj->GetSbxId() == SBXID_DIALOG ) )
1896     {
1897         bRet = true;
1898     }
1899     return bRet;
1900 }
1901 
1902 
1903 // Methods XNameReplace
1904 void DialogContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
1905 {
1906     removeByName( aName );
1907     insertByName( aName, aElement );
1908 }
1909 
1910 
1911 // Methods XNameContainer
1912 void DialogContainer_Impl::insertByName( const OUString&, const uno::Any& aElement )
1913 {
1914     uno::Type aModuleType = cppu::UnoType<script::XStarBasicDialogInfo>::get();
1915     const uno::Type& aAnyType = aElement.getValueType();
1916     if( aModuleType != aAnyType )
1917     {
1918         throw lang::IllegalArgumentException();
1919     }
1920     uno::Reference< script::XStarBasicDialogInfo > xMod;
1921     aElement >>= xMod;
1922     SbxObjectRef xDialog = implCreateDialog( xMod->getData() );
1923     mpLib->Insert( xDialog.get() );
1924 }
1925 
1926 void DialogContainer_Impl::removeByName( const OUString& Name )
1927 {
1928     SbxVariable* pVar = mpLib->GetObjects()->Find( Name, SbxClassType::DontCare );
1929     SbxObject* pObj = dynamic_cast<SbxObject*>(pVar);
1930     if( !( pObj && ( pObj->GetSbxId() == SBXID_DIALOG ) ) )
1931     {
1932         throw container::NoSuchElementException();
1933     }
1934     mpLib->Remove( pVar );
1935 }
1936 
1937 
1938 class LibraryContainer_Impl : public NameContainerHelper
1939 {
1940     BasicManager* mpMgr;
1941 
1942 public:
1943     explicit LibraryContainer_Impl( BasicManager* pMgr )
1944         :mpMgr( pMgr ) {}
1945 
1946     // Methods XElementAccess
1947     virtual uno::Type SAL_CALL getElementType() override;
1948     virtual sal_Bool SAL_CALL hasElements() override;
1949 
1950     // Methods XNameAccess
1951     virtual uno::Any SAL_CALL getByName( const OUString& aName ) override;
1952     virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
1953     virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
1954 
1955     // Methods XNameReplace
1956     virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override;
1957 
1958     // Methods XNameContainer
1959     virtual void SAL_CALL insertByName( const OUString& aName, const uno::Any& aElement ) override;
1960     virtual void SAL_CALL removeByName( const OUString& Name ) override;
1961 };
1962 
1963 
1964 // Methods XElementAccess
1965 uno::Type LibraryContainer_Impl::getElementType()
1966 {
1967     uno::Type aType = cppu::UnoType<script::XStarBasicLibraryInfo>::get();
1968     return aType;
1969 }
1970 
1971 sal_Bool LibraryContainer_Impl::hasElements()
1972 {
1973     sal_Int32 nLibs = mpMgr->GetLibCount();
1974     bool bRet = (nLibs > 0);
1975     return bRet;
1976 }
1977 
1978 // Methods XNameAccess
1979 uno::Any LibraryContainer_Impl::getByName( const OUString& aName )
1980 {
1981     uno::Any aRetAny;
1982     if( !mpMgr->HasLib( aName ) )
1983         throw container::NoSuchElementException();
1984     StarBASIC* pLib = mpMgr->GetLib( aName );
1985 
1986     uno::Reference< container::XNameContainer > xModuleContainer =
1987         new ModuleContainer_Impl( pLib );
1988 
1989     uno::Reference< container::XNameContainer > xDialogContainer =
1990         new DialogContainer_Impl( pLib );
1991 
1992     BasicLibInfo* pLibInfo = mpMgr->FindLibInfo( pLib );
1993 
1994     OUString aPassword = pLibInfo->GetPassword();
1995 
1996     // TODO Only provide extern info!
1997     OUString aExternaleSourceURL;
1998     OUString aLinkTargetURL;
1999     if( pLibInfo->IsReference() )
2000     {
2001         aLinkTargetURL = pLibInfo->GetStorageName();
2002     }
2003     else if( pLibInfo->IsExtern() )
2004     {
2005         aExternaleSourceURL = pLibInfo->GetStorageName();
2006     }
2007     uno::Reference< script::XStarBasicLibraryInfo > xLibInfo = new LibraryInfo_Impl
2008     (
2009         aName,
2010         xModuleContainer,
2011         xDialogContainer,
2012         aPassword,
2013         aExternaleSourceURL,
2014         aLinkTargetURL
2015     );
2016 
2017     aRetAny <<= xLibInfo;
2018     return aRetAny;
2019 }
2020 
2021 uno::Sequence< OUString > LibraryContainer_Impl::getElementNames()
2022 {
2023     sal_uInt16 nLibs = mpMgr->GetLibCount();
2024     uno::Sequence< OUString > aRetSeq( nLibs );
2025     OUString* pRetSeq = aRetSeq.getArray();
2026     for( sal_uInt16 i = 0 ; i < nLibs ; i++ )
2027     {
2028         pRetSeq[i] = mpMgr->GetLibName( i );
2029     }
2030     return aRetSeq;
2031 }
2032 
2033 sal_Bool LibraryContainer_Impl::hasByName( const OUString& aName )
2034 {
2035     bool bRet = mpMgr->HasLib( aName );
2036     return bRet;
2037 }
2038 
2039 // Methods XNameReplace
2040 void LibraryContainer_Impl::replaceByName( const OUString& aName, const uno::Any& aElement )
2041 {
2042     removeByName( aName );
2043     insertByName( aName, aElement );
2044 }
2045 
2046 // Methods XNameContainer
2047 void LibraryContainer_Impl::insertByName( const OUString&, const uno::Any& )
2048 {
2049     // TODO: Insert a complete Library?!
2050 }
2051 
2052 void LibraryContainer_Impl::removeByName( const OUString& Name )
2053 {
2054     StarBASIC* pLib = mpMgr->GetLib( Name );
2055     if( !pLib )
2056     {
2057         throw container::NoSuchElementException();
2058     }
2059     sal_uInt16 nLibId = mpMgr->GetLibId( Name );
2060     mpMgr->RemoveLib( nLibId );
2061 }
2062 
2063 
2064 typedef WeakImplHelper< script::XStarBasicAccess > StarBasicAccessHelper;
2065 
2066 
2067 class StarBasicAccess_Impl : public StarBasicAccessHelper
2068 {
2069     BasicManager* mpMgr;
2070     uno::Reference< container::XNameContainer > mxLibContainer;
2071 
2072 public:
2073     explicit StarBasicAccess_Impl( BasicManager* pMgr )
2074         :mpMgr( pMgr ) {}
2075 
2076 public:
2077     // Methods
2078     virtual uno::Reference< container::XNameContainer > SAL_CALL getLibraryContainer() override;
2079     virtual void SAL_CALL createLibrary( const OUString& LibName, const OUString& Password,
2080         const OUString& ExternalSourceURL, const OUString& LinkTargetURL ) override;
2081     virtual void SAL_CALL addModule( const OUString& LibraryName, const OUString& ModuleName,
2082         const OUString& Language, const OUString& Source ) override;
2083     virtual void SAL_CALL addDialog( const OUString& LibraryName, const OUString& DialogName,
2084         const uno::Sequence< sal_Int8 >& Data ) override;
2085 };
2086 
2087 uno::Reference< container::XNameContainer > SAL_CALL StarBasicAccess_Impl::getLibraryContainer()
2088 {
2089     if( !mxLibContainer.is() )
2090         mxLibContainer = new LibraryContainer_Impl( mpMgr );
2091     return mxLibContainer;
2092 }
2093 
2094 void SAL_CALL StarBasicAccess_Impl::createLibrary
2095 (
2096     const OUString& LibName,
2097     const OUString& Password,
2098     const OUString&,
2099     const OUString& LinkTargetURL
2100 )
2101 {
2102     StarBASIC* pLib = mpMgr->CreateLib( LibName, Password, LinkTargetURL );
2103     DBG_ASSERT( pLib, "XML Import: Basic library could not be created");
2104 }
2105 
2106 void SAL_CALL StarBasicAccess_Impl::addModule
2107 (
2108     const OUString& LibraryName,
2109     const OUString& ModuleName,
2110     const OUString&,
2111     const OUString& Source
2112 )
2113 {
2114     StarBASIC* pLib = mpMgr->GetLib( LibraryName );
2115     DBG_ASSERT( pLib, "XML Import: Lib for module unknown");
2116     if( pLib )
2117     {
2118         pLib->MakeModule( ModuleName, Source );
2119     }
2120 }
2121 
2122 void SAL_CALL StarBasicAccess_Impl::addDialog
2123 (
2124     const OUString&,
2125     const OUString&,
2126     const uno::Sequence< sal_Int8 >&
2127 )
2128 {}
2129 
2130 // Basic XML Import/Export
2131 uno::Reference< script::XStarBasicAccess > getStarBasicAccess( BasicManager* pMgr )
2132 {
2133     uno::Reference< script::XStarBasicAccess > xRet =
2134         new StarBasicAccess_Impl( pMgr );
2135     return xRet;
2136 }
2137 
2138 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2139