xref: /core/basic/source/uno/namecont.cxx (revision 58abc742)
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 <config_extensions.h>
21 #include <config_folders.h>
22 
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/container/XContainer.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XTransactedObject.hpp>
27 #include <com/sun/star/io/IOException.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/lang/XServiceInfo.hpp>
30 #include <com/sun/star/ucb/ContentCreationException.hpp>
31 #include <com/sun/star/xml/sax/SAXException.hpp>
32 #include <vcl/svapp.hxx>
33 #include <osl/mutex.hxx>
34 #include <vcl/errinf.hxx>
35 #include <rtl/ustring.hxx>
36 #include <rtl/strbuf.hxx>
37 #include <sal/log.hxx>
38 #include <comphelper/getexpandeduri.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/anytostring.hxx>
41 #include <comphelper/sequence.hxx>
42 
43 #include <namecont.hxx>
44 #include <basic/basicmanagerrepository.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <tools/urlobj.hxx>
47 #include <unotools/streamwrap.hxx>
48 #include <unotools/pathoptions.hxx>
49 #include <svtools/sfxecode.hxx>
50 #include <svtools/ehdl.hxx>
51 #include <basic/basmgr.hxx>
52 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
53 #include <com/sun/star/xml/sax/Parser.hpp>
54 #include <com/sun/star/xml/sax/InputSource.hpp>
55 #include <com/sun/star/io/XOutputStream.hpp>
56 #include <com/sun/star/xml/sax/Writer.hpp>
57 #include <com/sun/star/io/XInputStream.hpp>
58 #include <com/sun/star/io/XActiveDataSource.hpp>
59 #include <com/sun/star/beans/XPropertySet.hpp>
60 #include <com/sun/star/uno/DeploymentException.hpp>
61 #include <com/sun/star/lang/DisposedException.hpp>
62 #include <com/sun/star/script/LibraryNotLoadedException.hpp>
63 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
64 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
65 #include <com/sun/star/util/PathSubstitution.hpp>
66 #include <com/sun/star/deployment/ExtensionManager.hpp>
67 #include <comphelper/storagehelper.hxx>
68 #include <cppuhelper/exc_hlp.hxx>
69 #include <cppuhelper/queryinterface.hxx>
70 #include <cppuhelper/supportsservice.hxx>
71 #include <basic/sbmod.hxx>
72 #include <memory>
73 
74 namespace basic
75 {
76 
77 using namespace com::sun::star::document;
78 using namespace com::sun::star::container;
79 using namespace com::sun::star::uno;
80 using namespace com::sun::star::lang;
81 using namespace com::sun::star::io;
82 using namespace com::sun::star::ucb;
83 using namespace com::sun::star::script;
84 using namespace com::sun::star::beans;
85 using namespace com::sun::star::xml::sax;
86 using namespace com::sun::star::util;
87 using namespace com::sun::star::task;
88 using namespace com::sun::star::embed;
89 using namespace com::sun::star::frame;
90 using namespace com::sun::star::deployment;
91 using namespace com::sun::star;
92 using namespace cppu;
93 using namespace osl;
94 
95 using com::sun::star::uno::Reference;
96 
97 // #i34411: Flag for error handling during migration
98 static bool GbMigrationSuppressErrors = false;
99 
100 
101 // Implementation class NameContainer
102 
103 // Methods XElementAccess
104 Type NameContainer::getElementType()
105 {
106     return mType;
107 }
108 
109 sal_Bool NameContainer::hasElements()
110 {
111     bool bRet = (mnElementCount > 0);
112     return bRet;
113 }
114 
115 // Methods XNameAccess
116 Any NameContainer::getByName( const OUString& aName )
117 {
118     NameContainerNameMap::iterator aIt = mHashMap.find( aName );
119     if( aIt == mHashMap.end() )
120     {
121         throw NoSuchElementException();
122     }
123     sal_Int32 iHashResult = (*aIt).second;
124     Any aRetAny = mValues[ iHashResult ];
125     return aRetAny;
126 }
127 
128 Sequence< OUString > NameContainer::getElementNames()
129 {
130     return comphelper::containerToSequence(mNames);
131 }
132 
133 sal_Bool NameContainer::hasByName( const OUString& aName )
134 {
135     NameContainerNameMap::iterator aIt = mHashMap.find( aName );
136     bool bRet = ( aIt != mHashMap.end() );
137     return bRet;
138 }
139 
140 
141 // Methods XNameReplace
142 void NameContainer::replaceByName( const OUString& aName, const Any& aElement )
143 {
144     const Type& aAnyType = aElement.getValueType();
145     if( mType != aAnyType )
146     {
147         throw IllegalArgumentException();
148     }
149     NameContainerNameMap::iterator aIt = mHashMap.find( aName );
150     if( aIt == mHashMap.end() )
151     {
152         throw NoSuchElementException();
153     }
154     sal_Int32 iHashResult = (*aIt).second;
155     Any aOldElement = mValues[ iHashResult ];
156     mValues[ iHashResult ] = aElement;
157 
158 
159     // Fire event
160     if( maContainerListeners.getLength() > 0 )
161     {
162         ContainerEvent aEvent;
163         aEvent.Source = mpxEventSource;
164         aEvent.Accessor <<= aName;
165         aEvent.Element = aElement;
166         aEvent.ReplacedElement = aOldElement;
167         maContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvent );
168     }
169 
170     /*  After the container event has been fired (one listener will update the
171         core Basic manager), fire change event. Listeners can rely on that the
172         Basic source code of the core Basic manager is up-to-date. */
173     if( maChangesListeners.getLength() > 0 )
174     {
175         ChangesEvent aEvent;
176         aEvent.Source = mpxEventSource;
177         aEvent.Base <<= aEvent.Source;
178         aEvent.Changes.realloc( 1 );
179         aEvent.Changes[ 0 ].Accessor <<= aName;
180         aEvent.Changes[ 0 ].Element = aElement;
181         aEvent.Changes[ 0 ].ReplacedElement = aOldElement;
182         maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
183     }
184 }
185 
186 void NameContainer::insertCheck(const OUString& aName, const Any& aElement)
187 {
188     NameContainerNameMap::iterator aIt = mHashMap.find(aName);
189     if( aIt != mHashMap.end() )
190     {
191         throw ElementExistException();
192     }
193     insertNoCheck(aName, aElement);
194 }
195 
196 void NameContainer::insertNoCheck(const OUString& aName, const Any& aElement)
197 {
198     const Type& aAnyType = aElement.getValueType();
199     if( mType != aAnyType )
200     {
201         throw IllegalArgumentException();
202     }
203 
204     sal_Int32 nCount = mNames.size();
205     mNames.push_back( aName );
206     mValues.push_back( aElement );
207 
208     mHashMap[ aName ] = nCount;
209     mnElementCount++;
210 
211     // Fire event
212     if( maContainerListeners.getLength() > 0 )
213     {
214         ContainerEvent aEvent;
215         aEvent.Source = mpxEventSource;
216         aEvent.Accessor <<= aName;
217         aEvent.Element = aElement;
218         maContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
219     }
220 
221     /*  After the container event has been fired (one listener will update the
222         core Basic manager), fire change event. Listeners can rely on that the
223         Basic source code of the core Basic manager is up-to-date. */
224     if( maChangesListeners.getLength() > 0 )
225     {
226         ChangesEvent aEvent;
227         aEvent.Source = mpxEventSource;
228         aEvent.Base <<= aEvent.Source;
229         aEvent.Changes.realloc( 1 );
230         aEvent.Changes[ 0 ].Accessor <<= aName;
231         aEvent.Changes[ 0 ].Element = aElement;
232         maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
233     }
234 }
235 
236 // Methods XNameContainer
237 void NameContainer::insertByName( const OUString& aName, const Any& aElement )
238 {
239     insertCheck(aName, aElement);
240 }
241 
242 void NameContainer::removeByName( const OUString& aName )
243 {
244     NameContainerNameMap::iterator aIt = mHashMap.find( aName );
245     if( aIt == mHashMap.end() )
246     {
247         OUString sMessage = "\"" + aName + "\" not found";
248         throw NoSuchElementException(sMessage);
249     }
250 
251     sal_Int32 iHashResult = (*aIt).second;
252     Any aOldElement = mValues[ iHashResult ];
253     mHashMap.erase( aIt );
254     sal_Int32 iLast = mNames.size() - 1;
255     if( iLast != iHashResult )
256     {
257         mNames[ iHashResult ] = mNames[ iLast ];
258         mValues[ iHashResult ] = mValues[ iLast ];
259         mHashMap[ mNames[ iHashResult ] ] = iHashResult;
260     }
261     mNames.resize( iLast );
262     mValues.resize( iLast );
263     mnElementCount--;
264 
265     // Fire event
266     if( maContainerListeners.getLength() > 0 )
267     {
268         ContainerEvent aEvent;
269         aEvent.Source = mpxEventSource;
270         aEvent.Accessor <<= aName;
271         aEvent.Element = aOldElement;
272         maContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
273     }
274 
275     /*  After the container event has been fired (one listener will update the
276         core Basic manager), fire change event. Listeners can rely on that the
277         Basic source code of the core Basic manager is up-to-date. */
278     if( maChangesListeners.getLength() > 0 )
279     {
280         ChangesEvent aEvent;
281         aEvent.Source = mpxEventSource;
282         aEvent.Base <<= aEvent.Source;
283         aEvent.Changes.realloc( 1 );
284         aEvent.Changes[ 0 ].Accessor <<= aName;
285         // aEvent.Changes[ 0 ].Element remains empty (meaning "replaced with nothing")
286         aEvent.Changes[ 0 ].ReplacedElement = aOldElement;
287         maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
288     }
289 }
290 
291 
292 // Methods XContainer
293 void SAL_CALL NameContainer::addContainerListener( const Reference< XContainerListener >& xListener )
294 {
295     if( !xListener.is() )
296     {
297         throw RuntimeException("addContainerListener called with null xListener");
298     }
299     maContainerListeners.addInterface( Reference<XInterface>(xListener, UNO_QUERY) );
300 }
301 
302 void SAL_CALL NameContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
303 {
304     if( !xListener.is() )
305     {
306         throw RuntimeException("removeContainerListener called with null xListener");
307     }
308     maContainerListeners.removeInterface( Reference<XInterface>(xListener, UNO_QUERY) );
309 }
310 
311 // Methods XChangesNotifier
312 void SAL_CALL NameContainer::addChangesListener( const Reference< XChangesListener >& xListener )
313 {
314     if( !xListener.is() )
315     {
316         throw RuntimeException("addChangesListener called with null xListener");
317     }
318     maChangesListeners.addInterface( Reference<XInterface>(xListener, UNO_QUERY) );
319 }
320 
321 void SAL_CALL NameContainer::removeChangesListener( const Reference< XChangesListener >& xListener )
322 {
323     if( !xListener.is() )
324     {
325         throw RuntimeException("removeChangesListener called with null xListener");
326     }
327     maChangesListeners.removeInterface( Reference<XInterface>(xListener, UNO_QUERY) );
328 }
329 
330 
331 // ModifiableHelper
332 
333 void ModifiableHelper::setModified( bool _bModified )
334 {
335     if ( _bModified == mbModified )
336     {
337         return;
338     }
339     mbModified = _bModified;
340 
341     if ( m_aModifyListeners.getLength() == 0 )
342     {
343         return;
344     }
345     EventObject aModifyEvent( m_rEventSource );
346     m_aModifyListeners.notifyEach( &XModifyListener::modified, aModifyEvent );
347 }
348 
349 
350 VBAScriptListenerContainer::VBAScriptListenerContainer( ::osl::Mutex& rMutex ) :
351     VBAScriptListenerContainer_BASE( rMutex )
352 {
353 }
354 
355 bool VBAScriptListenerContainer::implTypedNotify( const Reference< vba::XVBAScriptListener >& rxListener, const vba::VBAScriptEvent& rEvent )
356 {
357     rxListener->notifyVBAScriptEvent( rEvent );
358     return true;    // notify all other listeners too
359 }
360 
361 // Ctor
362 SfxLibraryContainer::SfxLibraryContainer()
363     : SfxLibraryContainer_BASE( m_aMutex )
364     , maVBAScriptListeners( m_aMutex )
365     , mnRunningVBAScripts( 0 )
366     , mbVBACompat( false )
367     , maModifiable( *this, m_aMutex )
368     , maNameContainer( new NameContainer(cppu::UnoType<XNameAccess>::get()) )
369     , mbOldInfoFormat( false )
370     , mbOasis2OOoFormat( false )
371     , mpBasMgr( nullptr )
372     , mbOwnBasMgr( false )
373     , meInitMode(DEFAULT)
374 {
375     mxContext = comphelper::getProcessComponentContext();
376 
377     mxSFI = ucb::SimpleFileAccess::create( mxContext );
378 
379     mxStringSubstitution = util::PathSubstitution::create( mxContext );
380 }
381 
382 SfxLibraryContainer::~SfxLibraryContainer()
383 {
384     if( mbOwnBasMgr )
385     {
386         delete mpBasMgr;
387     }
388 }
389 
390 void SfxLibraryContainer::enterMethod()
391 {
392     Application::GetSolarMutex().acquire();
393     if ( rBHelper.bInDispose || rBHelper.bDisposed )
394     {
395         throw DisposedException( OUString(), *this );
396     }
397 }
398 
399 void SfxLibraryContainer::leaveMethod()
400 {
401     Application::GetSolarMutex().release();
402 }
403 
404 BasicManager* SfxLibraryContainer::getBasicManager()
405 {
406     try
407     {
408         if ( mpBasMgr )
409         {
410             return mpBasMgr;
411         }
412         Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
413         SAL_WARN_IF(
414             !xDocument.is(), "basic",
415             ("SfxLibraryContainer::getBasicManager: cannot obtain a BasicManager"
416              " without document!"));
417         if ( xDocument.is() )
418         {
419             mpBasMgr = BasicManagerRepository::getDocumentBasicManager( xDocument );
420         }
421     }
422     catch (const css::ucb::ContentCreationException& e)
423     {
424         SAL_WARN( "basic", "SfxLibraryContainer::getBasicManager: " << e );
425     }
426     return mpBasMgr;
427 }
428 
429 // Methods XStorageBasedLibraryContainer
430 Reference< XStorage > SAL_CALL SfxLibraryContainer::getRootStorage()
431 {
432     LibraryContainerMethodGuard aGuard( *this );
433     return mxStorage;
434 }
435 
436 void SAL_CALL SfxLibraryContainer::setRootStorage( const Reference< XStorage >& _rxRootStorage )
437 {
438     LibraryContainerMethodGuard aGuard( *this );
439     if ( !_rxRootStorage.is() )
440     {
441         throw IllegalArgumentException();
442     }
443     mxStorage = _rxRootStorage;
444     onNewRootStorage();
445 }
446 
447 void SAL_CALL SfxLibraryContainer::storeLibrariesToStorage( const Reference< XStorage >& _rxRootStorage )
448 {
449     LibraryContainerMethodGuard aGuard( *this );
450     if ( !_rxRootStorage.is() )
451     {
452         throw IllegalArgumentException();
453     }
454     try
455     {
456         storeLibraries_Impl( _rxRootStorage, true );
457     }
458     catch( const Exception& )
459     {
460         throw WrappedTargetException( OUString(),
461                                       *this, ::cppu::getCaughtException() );
462     }
463 }
464 
465 
466 // Methods XModifiable
467 sal_Bool SfxLibraryContainer::isModified()
468 {
469     LibraryContainerMethodGuard aGuard( *this );
470     if ( maModifiable.isModified() )
471     {
472         return true;
473     }
474     // the library container is not modified, go through the libraries and check whether they are modified
475     Sequence< OUString > aNames = maNameContainer->getElementNames();
476     const OUString* pNames = aNames.getConstArray();
477     sal_Int32 nNameCount = aNames.getLength();
478 
479     for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
480     {
481         OUString aName = pNames[ i ];
482         try
483         {
484             SfxLibrary* pImplLib = getImplLib( aName );
485             if( pImplLib->isModified() )
486             {
487                 if ( aName == "Standard" )
488                 {
489                     // this is a workaround that has to be implemented because
490                     // empty standard library should stay marked as modified
491                     // but should not be treated as modified while it is empty
492                     if ( pImplLib->hasElements() )
493                         return true;
494                 }
495                 else
496                 {
497                     return true;
498                 }
499             }
500         }
501         catch(const css::container::NoSuchElementException&)
502         {
503         }
504     }
505 
506     return false;
507 }
508 
509 void SAL_CALL SfxLibraryContainer::setModified( sal_Bool _bModified )
510 {
511     LibraryContainerMethodGuard aGuard( *this );
512     maModifiable.setModified( _bModified );
513 }
514 
515 void SAL_CALL SfxLibraryContainer::addModifyListener( const Reference< XModifyListener >& _rxListener )
516 {
517     LibraryContainerMethodGuard aGuard( *this );
518     maModifiable.addModifyListener( _rxListener );
519 }
520 
521 void SAL_CALL SfxLibraryContainer::removeModifyListener( const Reference< XModifyListener >& _rxListener )
522 {
523     LibraryContainerMethodGuard aGuard( *this );
524     maModifiable.removeModifyListener( _rxListener );
525 }
526 
527 // Methods XPersistentLibraryContainer
528 Any SAL_CALL SfxLibraryContainer::getRootLocation()
529 {
530     LibraryContainerMethodGuard aGuard( *this );
531     return Any( getRootStorage() );
532 }
533 
534 OUString SAL_CALL SfxLibraryContainer::getContainerLocationName()
535 {
536     LibraryContainerMethodGuard aGuard( *this );
537     return maLibrariesDir;
538 }
539 
540 void SAL_CALL SfxLibraryContainer::storeLibraries(  )
541 {
542     LibraryContainerMethodGuard aGuard( *this );
543     try
544     {
545         storeLibraries_Impl( mxStorage, mxStorage.is()  );
546         // we need to store *all* libraries if and only if we are based on a storage:
547         // in this case, storeLibraries_Impl will remove the source storage, after loading
548         // all libraries, so we need to force them to be stored, again
549     }
550     catch( const Exception& )
551     {
552         throw WrappedTargetException( OUString(), *this, ::cppu::getCaughtException() );
553     }
554 }
555 
556 static void checkAndCopyFileImpl( const INetURLObject& rSourceFolderInetObj,
557                                   const INetURLObject& rTargetFolderInetObj,
558                                   const OUString& rCheckFileName,
559                                   const OUString& rCheckExtension,
560                                   const Reference< XSimpleFileAccess3 >& xSFI )
561 {
562     INetURLObject aTargetFolderInetObj( rTargetFolderInetObj );
563     aTargetFolderInetObj.insertName( rCheckFileName, true, INetURLObject::LAST_SEGMENT,
564                                      INetURLObject::EncodeMechanism::All );
565     aTargetFolderInetObj.setExtension( rCheckExtension );
566     OUString aTargetFile = aTargetFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
567     if( !xSFI->exists( aTargetFile ) )
568     {
569         INetURLObject aSourceFolderInetObj( rSourceFolderInetObj );
570         aSourceFolderInetObj.insertName( rCheckFileName, true, INetURLObject::LAST_SEGMENT,
571                                          INetURLObject::EncodeMechanism::All );
572         aSourceFolderInetObj.setExtension( rCheckExtension );
573         OUString aSourceFile = aSourceFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
574         xSFI->copy( aSourceFile, aTargetFile );
575     }
576 }
577 
578 static void createVariableURL( OUString& rStr, const OUString& rLibName,
579                                const OUString& rInfoFileName, bool bUser )
580 {
581     if( bUser )
582     {
583         rStr = "$(USER)/basic/";
584     }
585     else
586     {
587         rStr = "$(INST)/" LIBO_SHARE_FOLDER "/basic/";
588     }
589     rStr += rLibName + "/" + rInfoFileName + ".xlb/";
590 }
591 
592 void SfxLibraryContainer::init( const OUString& rInitialDocumentURL, const uno::Reference< embed::XStorage >& rxInitialStorage )
593 {
594     // this might be called from within the ctor, and the impl_init might (indirectly) create
595     // an UNO reference to ourself.
596     // Ensure that we're not destroyed while we're in here
597     osl_atomic_increment( &m_refCount );
598     init_Impl( rInitialDocumentURL, rxInitialStorage );
599     osl_atomic_decrement( &m_refCount );
600 }
601 
602 void SfxLibraryContainer::init_Impl( const OUString& rInitialDocumentURL,
603                                      const uno::Reference< embed::XStorage >& rxInitialStorage )
604 {
605     uno::Reference< embed::XStorage > xStorage = rxInitialStorage;
606 
607     maInitialDocumentURL = rInitialDocumentURL;
608     maInfoFileName = OUString::createFromAscii( getInfoFileName() );
609     maOldInfoFileName = OUString::createFromAscii( getOldInfoFileName() );
610     maLibElementFileExtension = OUString::createFromAscii( getLibElementFileExtension() );
611     maLibrariesDir = OUString::createFromAscii( getLibrariesDir() );
612 
613     meInitMode = DEFAULT;
614     INetURLObject aInitUrlInetObj( maInitialDocumentURL );
615     OUString aInitFileName = aInitUrlInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
616     if( !aInitFileName.isEmpty() )
617     {
618         // We need a BasicManager to avoid problems
619         StarBASIC* pBas = new StarBASIC();
620         mpBasMgr = new BasicManager( pBas );
621         mbOwnBasMgr = true;
622 
623         OUString aExtension = aInitUrlInetObj.getExtension();
624         if( aExtension == "xlc" )
625         {
626             meInitMode = CONTAINER_INIT_FILE;
627             INetURLObject aLibPathInetObj( aInitUrlInetObj );
628             aLibPathInetObj.removeSegment();
629             maLibraryPath = aLibPathInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
630         }
631         else if( aExtension == "xlb" )
632         {
633             meInitMode = LIBRARY_INIT_FILE;
634             uno::Reference< embed::XStorage > xDummyStor;
635             ::xmlscript::LibDescriptor aLibDesc;
636             implLoadLibraryIndexFile( nullptr, aLibDesc, xDummyStor, aInitFileName );
637             return;
638         }
639         else
640         {
641             // Decide between old and new document
642             bool bOldStorage = SotStorage::IsOLEStorage( aInitFileName );
643             if ( bOldStorage )
644             {
645                 meInitMode = OLD_BASIC_STORAGE;
646                 importFromOldStorage( aInitFileName );
647                 return;
648             }
649             else
650             {
651                 meInitMode = OFFICE_DOCUMENT;
652                 try
653                 {
654                     xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( aInitFileName, embed::ElementModes::READ );
655                 }
656                 catch (const uno::Exception& )
657                 {
658                     // TODO: error handling
659                 }
660             }
661         }
662     }
663     else
664     {
665         // Default paths
666         maLibraryPath = SvtPathOptions().GetBasicPath();
667     }
668 
669     Reference< XParser > xParser = xml::sax::Parser::create(mxContext);
670 
671     uno::Reference< io::XInputStream > xInput;
672 
673     mxStorage = xStorage;
674     bool bStorage = mxStorage.is();
675 
676 
677     // #110009: Scope to force the StorageRefs to be destructed and
678     // so the streams to be closed before the preload operation
679     {
680 
681     uno::Reference< embed::XStorage > xLibrariesStor;
682     OUString aFileName;
683 
684     int nPassCount = 1;
685     if( !bStorage && meInitMode == DEFAULT )
686     {
687         nPassCount = 2;
688     }
689     for( int nPass = 0 ; nPass < nPassCount ; nPass++ )
690     {
691         if( bStorage )
692         {
693             SAL_WARN_IF(
694                 meInitMode != DEFAULT && meInitMode != OFFICE_DOCUMENT, "basic",
695                 "Wrong InitMode for document");
696             try
697             {
698                 uno::Reference< io::XStream > xStream;
699                 xLibrariesStor = xStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
700 
701                 if ( xLibrariesStor.is() )
702                 {
703                     aFileName = maInfoFileName + "-lc.xml";
704                     try
705                     {
706                         xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
707                     }
708                     catch(const uno::Exception& )
709                     {}
710 
711                     if( !xStream.is() )
712                     {
713                         mbOldInfoFormat = true;
714 
715                         // Check old version
716                         aFileName = maOldInfoFileName + ".xml";
717                         try
718                         {
719                             xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
720                         }
721                         catch(const uno::Exception& )
722                         {}
723 
724                         if( !xStream.is() )
725                         {
726                             // Check for EA2 document version with wrong extensions
727                             aFileName = maOldInfoFileName + ".xli";
728                             xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
729                         }
730                     }
731                 }
732 
733                 if ( xStream.is() )
734                 {
735                     xInput = xStream->getInputStream();
736                 }
737             }
738             catch(const uno::Exception& )
739             {
740                 // TODO: error handling?
741             }
742         }
743         else
744         {
745             std::unique_ptr<INetURLObject> pLibInfoInetObj;
746             if( meInitMode == CONTAINER_INIT_FILE )
747             {
748                 aFileName = aInitFileName;
749             }
750             else
751             {
752                 if( nPass == 1 )
753                 {
754                     pLibInfoInetObj.reset(new INetURLObject( maLibraryPath.getToken(0, ';') ));
755                 }
756                 else
757                 {
758                     pLibInfoInetObj.reset(new INetURLObject( maLibraryPath.getToken(1, ';') ));
759                 }
760                 pLibInfoInetObj->insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
761                 pLibInfoInetObj->setExtension( "xlc" );
762                 aFileName = pLibInfoInetObj->GetMainURL( INetURLObject::DecodeMechanism::NONE );
763             }
764 
765             try
766             {
767                 xInput = mxSFI->openFileRead( aFileName );
768             }
769             catch(const Exception& )
770             {
771                 // Silently tolerate empty or missing files
772                 xInput.clear();
773             }
774 
775             // Old variant?
776             if( !xInput.is() && nPass == 0 )
777             {
778                 INetURLObject aLibInfoInetObj( maLibraryPath.getToken(1, ';') );
779                 aLibInfoInetObj.insertName( maOldInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
780                 aLibInfoInetObj.setExtension( "xli" );
781                 aFileName = aLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
782 
783                 try
784                 {
785                     xInput = mxSFI->openFileRead( aFileName );
786                     mbOldInfoFormat = true;
787                 }
788                 catch(const Exception& )
789                 {
790                     xInput.clear();
791                 }
792             }
793         }
794 
795         if( xInput.is() )
796         {
797             InputSource source;
798             source.aInputStream = xInput;
799             source.sSystemId    = aFileName;
800 
801             // start parsing
802             std::unique_ptr< ::xmlscript::LibDescriptorArray> pLibArray(new ::xmlscript::LibDescriptorArray());
803 
804             try
805             {
806                 xParser->setDocumentHandler( ::xmlscript::importLibraryContainer( pLibArray.get() ) );
807                 xParser->parseStream( source );
808             }
809             catch ( const xml::sax::SAXException& e )
810             {
811                 SAL_WARN("basic", e);
812                 return;
813             }
814             catch ( const io::IOException& e )
815             {
816                 SAL_WARN("basic", e);
817                 return;
818             }
819 
820             sal_Int32 nLibCount = pLibArray->mnLibCount;
821             for( sal_Int32 i = 0 ; i < nLibCount ; i++ )
822             {
823                 ::xmlscript::LibDescriptor& rLib = pLibArray->mpLibs[i];
824 
825                 // Check storage URL
826                 OUString aStorageURL = rLib.aStorageURL;
827                 if( !bStorage && aStorageURL.isEmpty() && nPass == 0 )
828                 {
829                     OUString aLibraryPath;
830                     if( meInitMode == CONTAINER_INIT_FILE )
831                     {
832                         aLibraryPath = maLibraryPath;
833                     }
834                     else
835                     {
836                         aLibraryPath = maLibraryPath.getToken(1, ';');
837                     }
838                     INetURLObject aInetObj( aLibraryPath );
839 
840                     aInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT,
841                                          INetURLObject::EncodeMechanism::All );
842                     OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
843                     if( mxSFI->isFolder( aLibDirPath ) )
844                     {
845                         createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, true );
846                         maModifiable.setModified( true );
847                     }
848                     else if( rLib.bLink )
849                     {
850                         // Check "share" path
851                         INetURLObject aShareInetObj( maLibraryPath.getToken(0, ';') );
852                         aShareInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT,
853                                                   INetURLObject::EncodeMechanism::All );
854                         OUString aShareLibDirPath = aShareInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
855                         if( mxSFI->isFolder( aShareLibDirPath ) )
856                         {
857                             createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, false );
858                             maModifiable.setModified( true );
859                         }
860                         else
861                         {
862                             // #i25537: Ignore lib if library folder does not really exist
863                             continue;
864                         }
865                     }
866                 }
867 
868                 OUString aLibName = rLib.aName;
869 
870                 // If the same library name is used by the shared and the
871                 // user lib container index files the user file wins
872                 if( nPass == 1 && hasByName( aLibName ) )
873                 {
874                     continue;
875                 }
876                 SfxLibrary* pImplLib;
877                 if( rLib.bLink )
878                 {
879                     Reference< XNameAccess > xLib =
880                         createLibraryLink( aLibName, rLib.aStorageURL, rLib.bReadOnly );
881                     pImplLib = static_cast< SfxLibrary* >( xLib.get() );
882                 }
883                 else
884                 {
885                     Reference< XNameContainer > xLib = createLibrary( aLibName );
886                     pImplLib = static_cast< SfxLibrary* >( xLib.get() );
887                     pImplLib->mbLoaded = false;
888                     pImplLib->mbReadOnly = rLib.bReadOnly;
889                     if( !bStorage )
890                     {
891                         checkStorageURL( rLib.aStorageURL, pImplLib->maLibInfoFileURL,
892                                          pImplLib->maStorageURL, pImplLib->maUnexpandedStorageURL );
893                     }
894                 }
895                 maModifiable.setModified( false );
896 
897                 // Read library info files
898                 if( !mbOldInfoFormat )
899                 {
900                     uno::Reference< embed::XStorage > xLibraryStor;
901                     if( !pImplLib->mbInitialised && bStorage )
902                     {
903                         try
904                         {
905                             xLibraryStor = xLibrariesStor->openStorageElement( rLib.aName,
906                                                                                 embed::ElementModes::READ );
907                         }
908                         catch(const uno::Exception& )
909                         {
910                             #if OSL_DEBUG_LEVEL > 0
911                             Any aError( ::cppu::getCaughtException() );
912                             SAL_WARN(
913                                 "basic",
914                                 "couldn't open sub storage for library \""
915                                     << rLib.aName << "\". Exception: "
916                                     << comphelper::anyToString(aError));
917                             #endif
918                         }
919                     }
920 
921                     // Link is already initialised in createLibraryLink()
922                     if( !pImplLib->mbInitialised && (!bStorage || xLibraryStor.is()) )
923                     {
924                         bool bLoaded = implLoadLibraryIndexFile( pImplLib, rLib, xLibraryStor, OUString() );
925                         SAL_WARN_IF(
926                             bLoaded && aLibName != rLib.aName, "basic",
927                             ("Different library names in library container and"
928                              " library info files!"));
929                         if( GbMigrationSuppressErrors && !bLoaded )
930                         {
931                             removeLibrary( aLibName );
932                         }
933                     }
934                 }
935                 else if( !bStorage )
936                 {
937                     // Write new index file immediately because otherwise
938                     // the library elements will be lost when storing into
939                     // the new info format
940                     uno::Reference< embed::XStorage > xTmpStorage;
941                     implStoreLibraryIndexFile( pImplLib, rLib, xTmpStorage );
942                 }
943 
944                 implImportLibDescriptor( pImplLib, rLib );
945 
946                 if( nPass == 1 )
947                 {
948                     pImplLib->mbSharedIndexFile = true;
949                     pImplLib->mbReadOnly = true;
950                 }
951             }
952 
953             // Keep flag for documents to force writing the new index files
954             if( !bStorage )
955             {
956                 mbOldInfoFormat = false;
957             }
958         }
959     }
960 
961     // #110009: END Scope to force the StorageRefs to be destructed
962     }
963 
964     if( !bStorage && meInitMode == DEFAULT )
965     {
966         try
967         {
968             implScanExtensions();
969         }
970         catch(const uno::Exception& )
971         {
972             // TODO: error handling?
973             SAL_WARN("basic", "Cannot access extensions!");
974         }
975     }
976 
977     // Preload?
978     {
979         Sequence< OUString > aNames = maNameContainer->getElementNames();
980         const OUString* pNames = aNames.getConstArray();
981         sal_Int32 nNameCount = aNames.getLength();
982         for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
983         {
984             OUString aName = pNames[ i ];
985             SfxLibrary* pImplLib = getImplLib( aName );
986             if( pImplLib->mbPreload )
987             {
988                 loadLibrary( aName );
989             }
990         }
991     }
992 
993     if( meInitMode == DEFAULT )
994     {
995         INetURLObject aUserBasicInetObj( maLibraryPath.getToken(1, ';') );
996         OUString aStandardStr("Standard");
997 
998         INetURLObject aPrevUserBasicInetObj_1( aUserBasicInetObj );
999         aPrevUserBasicInetObj_1.removeSegment();
1000         INetURLObject aPrevUserBasicInetObj_2 = aPrevUserBasicInetObj_1;
1001         aPrevUserBasicInetObj_1.Append( "__basic_80" );
1002         aPrevUserBasicInetObj_2.Append( "__basic_80_2" );
1003 
1004         // #i93163
1005         bool bCleanUp = false;
1006         try
1007         {
1008             INetURLObject aPrevUserBasicInetObj = aPrevUserBasicInetObj_1;
1009             OUString aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1010             if( mxSFI->isFolder( aPrevFolder ) )
1011             {
1012                 // Check if Standard folder exists and is complete
1013                 INetURLObject aUserBasicStandardInetObj( aUserBasicInetObj );
1014                 aUserBasicStandardInetObj.insertName( aStandardStr, true, INetURLObject::LAST_SEGMENT,
1015                                                       INetURLObject::EncodeMechanism::All );
1016                 INetURLObject aPrevUserBasicStandardInetObj( aPrevUserBasicInetObj );
1017                 aPrevUserBasicStandardInetObj.insertName( aStandardStr, true, INetURLObject::LAST_SEGMENT,
1018                                                         INetURLObject::EncodeMechanism::All );
1019                 OUString aPrevStandardFolder = aPrevUserBasicStandardInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1020                 if( mxSFI->isFolder( aPrevStandardFolder ) )
1021                 {
1022                     OUString aXlbExtension( "xlb" );
1023                     OUString aCheckFileName;
1024 
1025                     // Check if script.xlb exists
1026                     aCheckFileName = "script";
1027                     checkAndCopyFileImpl( aUserBasicStandardInetObj,
1028                                           aPrevUserBasicStandardInetObj,
1029                                           aCheckFileName, aXlbExtension, mxSFI );
1030 
1031                     // Check if dialog.xlb exists
1032                     aCheckFileName = "dialog";
1033                     checkAndCopyFileImpl( aUserBasicStandardInetObj,
1034                                           aPrevUserBasicStandardInetObj,
1035                                           aCheckFileName, aXlbExtension, mxSFI );
1036 
1037                     // Check if module1.xba exists
1038                     aCheckFileName = "Module1";
1039                     checkAndCopyFileImpl( aUserBasicStandardInetObj,
1040                                           aPrevUserBasicStandardInetObj,
1041                                           aCheckFileName, "xba", mxSFI );
1042                 }
1043                 else
1044                 {
1045                     OUString aStandardFolder = aUserBasicStandardInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1046                     mxSFI->copy( aStandardFolder, aPrevStandardFolder );
1047                 }
1048 
1049                 OUString aPrevCopyToFolder = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1050                 mxSFI->copy( aPrevFolder, aPrevCopyToFolder );
1051             }
1052             else
1053             {
1054                 aPrevUserBasicInetObj = aPrevUserBasicInetObj_2;
1055                 aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1056             }
1057             if( mxSFI->isFolder( aPrevFolder ) )
1058             {
1059                 rtl::Reference<SfxLibraryContainer> pPrevCont = createInstanceImpl();
1060 
1061                 // Rename previous basic folder to make storage URLs correct during initialisation
1062                 OUString aFolderUserBasic = aUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1063                 INetURLObject aUserBasicTmpInetObj( aUserBasicInetObj );
1064                 aUserBasicTmpInetObj.removeSegment();
1065                 aUserBasicTmpInetObj.Append( "__basic_tmp" );
1066                 OUString aFolderTmp = aUserBasicTmpInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1067 
1068                 mxSFI->move( aFolderUserBasic, aFolderTmp );
1069                 try
1070                 {
1071                     mxSFI->move( aPrevFolder, aFolderUserBasic );
1072                 }
1073                 catch(const Exception& )
1074                 {
1075                     // Move back user/basic folder
1076                     try
1077                     {
1078                            mxSFI->kill( aFolderUserBasic );
1079                     }
1080                     catch(const Exception& )
1081                     {}
1082                     mxSFI->move( aFolderTmp, aFolderUserBasic );
1083                     throw;
1084                 }
1085 
1086                 INetURLObject aPrevUserBasicLibInfoInetObj( aUserBasicInetObj );
1087                 aPrevUserBasicLibInfoInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT,
1088                                                     INetURLObject::EncodeMechanism::All );
1089                 aPrevUserBasicLibInfoInetObj.setExtension( "xlc");
1090                 OUString aLibInfoFileName = aPrevUserBasicLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1091                 Sequence<Any> aInitSeq( 1 );
1092                 aInitSeq.getArray()[0] <<= aLibInfoFileName;
1093                 GbMigrationSuppressErrors = true;
1094                 pPrevCont->initialize( aInitSeq );
1095                 GbMigrationSuppressErrors = false;
1096 
1097                 // Rename folders back
1098                 mxSFI->move( aFolderUserBasic, aPrevFolder );
1099                 mxSFI->move( aFolderTmp, aFolderUserBasic );
1100 
1101                 Sequence< OUString > aNames = pPrevCont->getElementNames();
1102                 const OUString* pNames = aNames.getConstArray();
1103                 sal_Int32 nNameCount = aNames.getLength();
1104 
1105                 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
1106                 {
1107                     OUString aLibName = pNames[ i ];
1108                     if( hasByName( aLibName ) )
1109                     {
1110                         if( aLibName == aStandardStr )
1111                         {
1112                             SfxLibrary* pImplLib = getImplLib( aStandardStr );
1113                             OUString aStandardFolder = pImplLib->maStorageURL;
1114                             mxSFI->kill( aStandardFolder );
1115                         }
1116                         else
1117                         {
1118                             continue;
1119                         }
1120                     }
1121 
1122                     SfxLibrary* pImplLib = pPrevCont->getImplLib( aLibName );
1123                     if( pImplLib->mbLink )
1124                     {
1125                         OUString aStorageURL = pImplLib->maUnexpandedStorageURL;
1126                         bool bCreateLink = true;
1127                         if( aStorageURL.indexOf( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE"   ) != -1 ||
1128                             aStorageURL.indexOf( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" ) != -1 ||
1129                             aStorageURL.indexOf( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" ) != -1 ||
1130                             aStorageURL.indexOf( "$(INST)"   ) != -1 )
1131                         {
1132                             bCreateLink = false;
1133                         }
1134                         if( bCreateLink )
1135                         {
1136                             createLibraryLink( aLibName, pImplLib->maStorageURL, pImplLib->mbReadOnly );
1137                         }
1138                     }
1139                     else
1140                     {
1141                         // Move folder if not already done
1142                         INetURLObject aUserBasicLibFolderInetObj( aUserBasicInetObj );
1143                         aUserBasicLibFolderInetObj.Append( aLibName );
1144                         OUString aLibFolder = aUserBasicLibFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1145 
1146                         INetURLObject aPrevUserBasicLibFolderInetObj( aPrevUserBasicInetObj );
1147                         aPrevUserBasicLibFolderInetObj.Append( aLibName );
1148                         OUString aPrevLibFolder = aPrevUserBasicLibFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1149 
1150                         if( mxSFI->isFolder( aPrevLibFolder ) && !mxSFI->isFolder( aLibFolder ) )
1151                         {
1152                             mxSFI->move( aPrevLibFolder, aLibFolder );
1153                         }
1154 
1155                         if( aLibName == aStandardStr )
1156                         {
1157                             maNameContainer->removeByName( aLibName );
1158                         }
1159 
1160                         // Create library
1161                         Reference< XNameContainer > xLib = createLibrary( aLibName );
1162                            SfxLibrary* pNewLib = static_cast< SfxLibrary* >( xLib.get() );
1163                         pNewLib->mbLoaded = false;
1164                         pNewLib->implSetModified( false );
1165                         checkStorageURL( aLibFolder, pNewLib->maLibInfoFileURL,
1166                                          pNewLib->maStorageURL, pNewLib->maUnexpandedStorageURL );
1167 
1168                         uno::Reference< embed::XStorage > xDummyStor;
1169                         ::xmlscript::LibDescriptor aLibDesc;
1170                         implLoadLibraryIndexFile( pNewLib, aLibDesc, xDummyStor, pNewLib->maLibInfoFileURL );
1171                         implImportLibDescriptor( pNewLib, aLibDesc );
1172                     }
1173                 }
1174                 mxSFI->kill( aPrevFolder );
1175             }
1176         }
1177         catch(const Exception& e)
1178         {
1179             bCleanUp = true;
1180             SAL_WARN("basic", "Upgrade of Basic installation failed somehow: " << e);
1181         }
1182 
1183         // #i93163
1184         if( bCleanUp )
1185         {
1186             INetURLObject aPrevUserBasicInetObj_Err( aUserBasicInetObj );
1187             aPrevUserBasicInetObj_Err.removeSegment();
1188             aPrevUserBasicInetObj_Err.Append( "__basic_80_err" );
1189             OUString aPrevFolder_Err = aPrevUserBasicInetObj_Err.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1190 
1191             bool bSaved = false;
1192             try
1193             {
1194                 OUString aPrevFolder_1 = aPrevUserBasicInetObj_1.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1195                 if( mxSFI->isFolder( aPrevFolder_1 ) )
1196                 {
1197                     mxSFI->move( aPrevFolder_1, aPrevFolder_Err );
1198                     bSaved = true;
1199                 }
1200             }
1201             catch(const Exception& )
1202             {}
1203             try
1204             {
1205                 OUString aPrevFolder_2 = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1206                 if( !bSaved && mxSFI->isFolder( aPrevFolder_2 ) )
1207                 {
1208                     mxSFI->move( aPrevFolder_2, aPrevFolder_Err );
1209                 }
1210                 else
1211                 {
1212                     mxSFI->kill( aPrevFolder_2 );
1213                 }
1214             }
1215             catch(const Exception& )
1216             {}
1217         }
1218     }
1219 }
1220 
1221 void SfxLibraryContainer::implScanExtensions()
1222 {
1223 #if HAVE_FEATURE_EXTENSIONS
1224     ScriptExtensionIterator aScriptIt;
1225     OUString aLibURL;
1226 
1227     bool bPureDialogLib = false;
1228     while ( !(aLibURL = aScriptIt.nextBasicOrDialogLibrary( bPureDialogLib )).isEmpty())
1229     {
1230         if( bPureDialogLib && maInfoFileName == "script" )
1231         {
1232             continue;
1233         }
1234         // Extract lib name
1235         sal_Int32 nLen = aLibURL.getLength();
1236         sal_Int32 indexLastSlash = aLibURL.lastIndexOf( '/' );
1237         sal_Int32 nReduceCopy = 0;
1238         if( indexLastSlash == nLen - 1 )
1239         {
1240             nReduceCopy = 1;
1241             indexLastSlash = aLibURL.lastIndexOf( '/', nLen - 1 );
1242         }
1243 
1244         OUString aLibName = aLibURL.copy( indexLastSlash + 1, nLen - indexLastSlash - nReduceCopy - 1 );
1245 
1246         // If a library of the same exists the existing library wins
1247         if( hasByName( aLibName ) )
1248         {
1249             continue;
1250         }
1251         // Add index file to URL
1252         OUString aIndexFileURL = aLibURL;
1253         if( nReduceCopy == 0 )
1254         {
1255             aIndexFileURL += "/";
1256         }
1257         aIndexFileURL += maInfoFileName + ".xlb";
1258 
1259         // Create link
1260         const bool bReadOnly = false;
1261         createLibraryLink( aLibName, aIndexFileURL, bReadOnly );
1262     }
1263 #else
1264     (void) this;
1265 #endif
1266 }
1267 
1268 // Handle maLibInfoFileURL and maStorageURL correctly
1269 void SfxLibraryContainer::checkStorageURL( const OUString& aSourceURL,
1270                                            OUString& aLibInfoFileURL, OUString& aStorageURL,
1271                                            OUString& aUnexpandedStorageURL )
1272 {
1273     OUString aExpandedSourceURL = expand_url( aSourceURL );
1274     if( aExpandedSourceURL != aSourceURL )
1275     {
1276         aUnexpandedStorageURL = aSourceURL;
1277     }
1278     INetURLObject aInetObj( aExpandedSourceURL );
1279     OUString aExtension = aInetObj.getExtension();
1280     if( aExtension == "xlb" )
1281     {
1282         // URL to xlb file
1283         aLibInfoFileURL = aExpandedSourceURL;
1284         aInetObj.removeSegment();
1285         aStorageURL = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1286     }
1287     else
1288     {
1289         // URL to library folder
1290         aStorageURL = aExpandedSourceURL;
1291         aInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
1292         aInetObj.setExtension( "xlb" );
1293         aLibInfoFileURL = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1294     }
1295 }
1296 
1297 SfxLibrary* SfxLibraryContainer::getImplLib( const OUString& rLibraryName )
1298 {
1299     Any aLibAny = maNameContainer->getByName( rLibraryName ) ;
1300     Reference< XNameAccess > xNameAccess;
1301     aLibAny >>= xNameAccess;
1302     SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
1303     return pImplLib;
1304 }
1305 
1306 
1307 // Storing with password encryption
1308 
1309 // Empty implementation, avoids unnecessary implementation in dlgcont.cxx
1310 bool SfxLibraryContainer::implStorePasswordLibrary( SfxLibrary*,
1311                                                     const OUString&,
1312                                                     const uno::Reference< embed::XStorage >&,
1313                                                     const uno::Reference< task::XInteractionHandler >&  )
1314 {
1315     return false;
1316 }
1317 
1318 bool SfxLibraryContainer::implStorePasswordLibrary(
1319     SfxLibrary* /*pLib*/,
1320     const OUString& /*aName*/,
1321     const css::uno::Reference< css::embed::XStorage >& /*xStorage*/,
1322     const OUString& /*aTargetURL*/,
1323     const Reference< XSimpleFileAccess3 >& /*xToUseSFI*/,
1324     const uno::Reference< task::XInteractionHandler >&  )
1325 {
1326     return false;
1327 }
1328 
1329 bool SfxLibraryContainer::implLoadPasswordLibrary(
1330     SfxLibrary* /*pLib*/,
1331     const OUString& /*Name*/,
1332     bool /*bVerifyPasswordOnly*/ )
1333 {
1334     return true;
1335 }
1336 
1337 OUString SfxLibraryContainer::createAppLibraryFolder( SfxLibrary* pLib, const OUString& aName )
1338 {
1339     OUString aLibDirPath = pLib->maStorageURL;
1340     if( aLibDirPath.isEmpty() )
1341     {
1342         INetURLObject aInetObj( maLibraryPath.getToken(1, ';') );
1343         aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
1344         checkStorageURL( aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), pLib->maLibInfoFileURL,
1345                          pLib->maStorageURL, pLib->maUnexpandedStorageURL );
1346         aLibDirPath = pLib->maStorageURL;
1347     }
1348 
1349     if( !mxSFI->isFolder( aLibDirPath ) )
1350     {
1351         try
1352         {
1353             mxSFI->createFolder( aLibDirPath );
1354         }
1355         catch(const Exception& )
1356         {}
1357     }
1358 
1359     return aLibDirPath;
1360 }
1361 
1362 // Storing
1363 void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
1364                                             const OUString& aName,
1365                                             const uno::Reference< embed::XStorage >& xStorage )
1366 {
1367     Reference< XSimpleFileAccess3 > xDummySFA;
1368     Reference< XInteractionHandler > xDummyHandler;
1369     implStoreLibrary( pLib, aName, xStorage, OUString(), xDummySFA, xDummyHandler );
1370 }
1371 
1372 // New variant for library export
1373 void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
1374                                             const OUString& aName,
1375                                             const uno::Reference< embed::XStorage >& xStorage,
1376                                             const OUString& aTargetURL,
1377                                             const Reference< XSimpleFileAccess3 >& rToUseSFI,
1378                                             const Reference< XInteractionHandler >& xHandler )
1379 {
1380     bool bLink = pLib->mbLink;
1381     bool bStorage = xStorage.is() && !bLink;
1382 
1383     Sequence< OUString > aElementNames = pLib->getElementNames();
1384     sal_Int32 nNameCount = aElementNames.getLength();
1385     const OUString* pNames = aElementNames.getConstArray();
1386 
1387     if( bStorage )
1388     {
1389         for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
1390         {
1391             OUString aElementName = pNames[ i ];
1392             OUString aStreamName = aElementName + ".xml";
1393 
1394             if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
1395             {
1396                 SAL_WARN(
1397                     "basic",
1398                     "invalid library element \"" << aElementName << '"');
1399                 continue;
1400             }
1401             try
1402             {
1403                 uno::Reference< io::XStream > xElementStream = xStorage->openStreamElement(
1404                                                                     aStreamName,
1405                                                                     embed::ElementModes::READWRITE );
1406                 //    throw uno::RuntimeException(); // TODO: method must either return the stream or throw an exception
1407 
1408                 uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
1409                 SAL_WARN_IF(
1410                     !xProps.is(), "basic",
1411                     "The StorageStream must implement XPropertySet interface!");
1412                 //if ( !xProps.is() ) //TODO
1413 
1414                 if ( xProps.is() )
1415                 {
1416                     xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
1417 
1418                     // #87671 Allow encryption
1419                     xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
1420 
1421                     Reference< XOutputStream > xOutput = xElementStream->getOutputStream();
1422                     Reference< XNameContainer > xLib( pLib );
1423                     writeLibraryElement( xLib, aElementName, xOutput );
1424                 }
1425             }
1426             catch(const uno::Exception& )
1427             {
1428                 SAL_WARN("basic", "Problem during storing of library!");
1429                 // TODO: error handling?
1430             }
1431         }
1432         pLib->storeResourcesToStorage( xStorage );
1433     }
1434     else
1435     {
1436         // Export?
1437         bool bExport = !aTargetURL.isEmpty();
1438         try
1439         {
1440             Reference< XSimpleFileAccess3 > xSFI = mxSFI;
1441             if( rToUseSFI.is() )
1442             {
1443                 xSFI = rToUseSFI;
1444             }
1445             OUString aLibDirPath;
1446             if( bExport )
1447             {
1448                 INetURLObject aInetObj( aTargetURL );
1449                 aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
1450                 aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1451 
1452                 if( !xSFI->isFolder( aLibDirPath ) )
1453                 {
1454                     xSFI->createFolder( aLibDirPath );
1455                 }
1456                 pLib->storeResourcesToURL( aLibDirPath, xHandler );
1457             }
1458             else
1459             {
1460                 aLibDirPath = createAppLibraryFolder( pLib, aName );
1461                 pLib->storeResources();
1462             }
1463 
1464             for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
1465             {
1466                 OUString aElementName = pNames[ i ];
1467 
1468                 INetURLObject aElementInetObj( aLibDirPath );
1469                 aElementInetObj.insertName( aElementName, false,
1470                                             INetURLObject::LAST_SEGMENT,
1471                                             INetURLObject::EncodeMechanism::All );
1472                 aElementInetObj.setExtension( maLibElementFileExtension );
1473                 OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1474 
1475                 if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
1476                 {
1477                     SAL_WARN(
1478                         "basic",
1479                         "invalid library element \"" << aElementName << '"');
1480                     continue;
1481                 }
1482 
1483                 // TODO: Check modified
1484                 try
1485                 {
1486                     if( xSFI->exists( aElementPath ) )
1487                     {
1488                         xSFI->kill( aElementPath );
1489                     }
1490                     Reference< XOutputStream > xOutput = xSFI->openFileWrite( aElementPath );
1491                     Reference< XNameContainer > xLib( pLib );
1492                     writeLibraryElement( xLib, aElementName, xOutput );
1493                     xOutput->closeOutput();
1494                 }
1495                 catch(const Exception& )
1496                 {
1497                     if( bExport )
1498                     {
1499                         throw;
1500                     }
1501                     SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aElementPath );
1502                     ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
1503                 }
1504             }
1505         }
1506         catch(const Exception& )
1507         {
1508             if( bExport )
1509             {
1510                 throw;
1511             }
1512         }
1513     }
1514 }
1515 
1516 void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
1517                                                      const ::xmlscript::LibDescriptor& rLib,
1518                                                      const uno::Reference< embed::XStorage >& xStorage )
1519 {
1520     Reference< XSimpleFileAccess3 > xDummySFA;
1521     implStoreLibraryIndexFile( pLib, rLib, xStorage, OUString(), xDummySFA );
1522 }
1523 
1524 // New variant for library export
1525 void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
1526                                                      const ::xmlscript::LibDescriptor& rLib,
1527                                                      const uno::Reference< embed::XStorage >& xStorage,
1528                                                      const OUString& aTargetURL,
1529                                                      const Reference< XSimpleFileAccess3 >& rToUseSFI )
1530 {
1531     // Create sax writer
1532     Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
1533 
1534     bool bLink = pLib->mbLink;
1535     bool bStorage = xStorage.is() && !bLink;
1536 
1537     // Write info file
1538     uno::Reference< io::XOutputStream > xOut;
1539     uno::Reference< io::XStream > xInfoStream;
1540     if( bStorage )
1541     {
1542         OUString aStreamName = maInfoFileName + "-lb.xml";
1543 
1544         try
1545         {
1546             xInfoStream = xStorage->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
1547             SAL_WARN_IF(!xInfoStream.is(), "basic", "No stream!");
1548             uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY );
1549             //    throw uno::RuntimeException(); // TODO
1550 
1551             if ( xProps.is() )
1552             {
1553                 xProps->setPropertyValue("MediaType", uno::Any( OUString("text/xml") ) );
1554 
1555                 // #87671 Allow encryption
1556                 xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
1557 
1558                 xOut = xInfoStream->getOutputStream();
1559             }
1560         }
1561         catch(const uno::Exception& )
1562         {
1563             SAL_WARN("basic", "Problem during storing of library index file!");
1564             // TODO: error handling?
1565         }
1566     }
1567     else
1568     {
1569         // Export?
1570         bool bExport = !aTargetURL.isEmpty();
1571         Reference< XSimpleFileAccess3 > xSFI = mxSFI;
1572         if( rToUseSFI.is() )
1573         {
1574             xSFI = rToUseSFI;
1575         }
1576         OUString aLibInfoPath;
1577         if( bExport )
1578         {
1579             INetURLObject aInetObj( aTargetURL );
1580             aInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
1581             OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1582             if( !xSFI->isFolder( aLibDirPath ) )
1583             {
1584                 xSFI->createFolder( aLibDirPath );
1585             }
1586             aInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
1587             aInetObj.setExtension( "xlb" );
1588             aLibInfoPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1589         }
1590         else
1591         {
1592             createAppLibraryFolder( pLib, rLib.aName );
1593             aLibInfoPath = pLib->maLibInfoFileURL;
1594         }
1595 
1596         try
1597         {
1598             if( xSFI->exists( aLibInfoPath ) )
1599             {
1600                 xSFI->kill( aLibInfoPath );
1601             }
1602             xOut = xSFI->openFileWrite( aLibInfoPath );
1603         }
1604         catch(const Exception& )
1605         {
1606             if( bExport )
1607             {
1608                 throw;
1609             }
1610             SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
1611             ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
1612         }
1613     }
1614     if( !xOut.is() )
1615     {
1616         SAL_WARN("basic", "couldn't open output stream");
1617         return;
1618     }
1619     xWriter->setOutputStream( xOut );
1620     xmlscript::exportLibrary( xWriter, rLib );
1621 }
1622 
1623 
1624 bool SfxLibraryContainer::implLoadLibraryIndexFile(  SfxLibrary* pLib,
1625                                                      ::xmlscript::LibDescriptor& rLib,
1626                                                      const uno::Reference< embed::XStorage >& xStorage,
1627                                                      const OUString& aIndexFileName )
1628 {
1629     Reference< XParser > xParser = xml::sax::Parser::create(mxContext);
1630 
1631     bool bStorage = false;
1632     if( pLib )
1633     {
1634         bool bLink = pLib->mbLink;
1635         bStorage = xStorage.is() && !bLink;
1636     }
1637 
1638     // Read info file
1639     uno::Reference< io::XInputStream > xInput;
1640     OUString aLibInfoPath;
1641     if( bStorage )
1642     {
1643         aLibInfoPath = maInfoFileName + "-lb.xml";
1644 
1645         try
1646         {
1647             uno::Reference< io::XStream > xInfoStream =
1648                 xStorage->openStreamElement( aLibInfoPath, embed::ElementModes::READ );
1649             xInput = xInfoStream->getInputStream();
1650         }
1651         catch(const uno::Exception& )
1652         {}
1653     }
1654     else
1655     {
1656         // Create Input stream
1657         //String aLibInfoPath; // attention: THIS PROBLEM MUST BE REVIEWED BY SCRIPTING OWNER!!!
1658 
1659         if( pLib )
1660         {
1661             createAppLibraryFolder( pLib, rLib.aName );
1662             aLibInfoPath = pLib->maLibInfoFileURL;
1663         }
1664         else
1665         {
1666             aLibInfoPath = aIndexFileName;
1667         }
1668         try
1669         {
1670             xInput = mxSFI->openFileRead( aLibInfoPath );
1671         }
1672         catch(const Exception& )
1673         {
1674             xInput.clear();
1675             if( !GbMigrationSuppressErrors )
1676             {
1677                 SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
1678                 ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
1679             }
1680         }
1681     }
1682     if( !xInput.is() )
1683     {
1684         return false;
1685     }
1686 
1687     InputSource source;
1688     source.aInputStream = xInput;
1689     source.sSystemId    = aLibInfoPath;
1690 
1691     // start parsing
1692     try
1693     {
1694         xParser->setDocumentHandler( ::xmlscript::importLibrary( rLib ) );
1695         xParser->parseStream( source );
1696     }
1697     catch(const Exception& )
1698     {
1699         SAL_WARN("basic", "Parsing error");
1700         SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
1701         ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
1702         return false;
1703     }
1704 
1705     if( !pLib )
1706     {
1707         Reference< XNameContainer > xLib = createLibrary( rLib.aName );
1708         pLib = static_cast< SfxLibrary* >( xLib.get() );
1709         pLib->mbLoaded = false;
1710         rLib.aStorageURL = aIndexFileName;
1711         checkStorageURL( rLib.aStorageURL, pLib->maLibInfoFileURL, pLib->maStorageURL,
1712                          pLib->maUnexpandedStorageURL );
1713 
1714         implImportLibDescriptor( pLib, rLib );
1715     }
1716 
1717     return true;
1718 }
1719 
1720 void SfxLibraryContainer::implImportLibDescriptor( SfxLibrary* pLib,
1721                                                    ::xmlscript::LibDescriptor const & rLib )
1722 {
1723     if( !pLib->mbInitialised )
1724     {
1725         sal_Int32 nElementCount = rLib.aElementNames.getLength();
1726         const OUString* pElementNames = rLib.aElementNames.getConstArray();
1727         Any aDummyElement = createEmptyLibraryElement();
1728         for( sal_Int32 i = 0 ; i < nElementCount ; i++ )
1729         {
1730             pLib->maNameContainer->insertByName( pElementNames[i], aDummyElement );
1731         }
1732         pLib->mbPasswordProtected = rLib.bPasswordProtected;
1733         pLib->mbReadOnly = rLib.bReadOnly;
1734         pLib->mbPreload  = rLib.bPreload;
1735         pLib->implSetModified( false );
1736         pLib->mbInitialised = true;
1737     }
1738 }
1739 
1740 
1741 // Methods of new XLibraryStorage interface?
1742 void SfxLibraryContainer::storeLibraries_Impl( const uno::Reference< embed::XStorage >& i_rStorage,
1743                                                bool bComplete )
1744 {
1745     const Sequence< OUString > aNames = maNameContainer->getElementNames();
1746     const sal_Int32 nNameCount = aNames.getLength();
1747     const OUString* pName = aNames.getConstArray();
1748     const OUString* pNamesEnd = aNames.getConstArray() + nNameCount;
1749 
1750     // Don't count libs from shared index file
1751     sal_Int32 nLibsToSave = nNameCount;
1752     for( ; pName != pNamesEnd; ++pName )
1753     {
1754         SfxLibrary* pImplLib = getImplLib( *pName );
1755         if( pImplLib->mbSharedIndexFile || pImplLib->mbExtension )
1756         {
1757             nLibsToSave--;
1758         }
1759     }
1760     // Write to storage?
1761     bool bStorage = i_rStorage.is();
1762     uno::Reference< embed::XStorage > xSourceLibrariesStor;
1763     uno::Reference< embed::XStorage > xTargetLibrariesStor;
1764     OUString sTempTargetStorName;
1765     const bool bInplaceStorage = bStorage && ( i_rStorage == mxStorage );
1766 
1767     if( nLibsToSave == 0 )
1768     {
1769         if ( bInplaceStorage && mxStorage->hasByName(maLibrariesDir) )
1770         {
1771             mxStorage->removeElement(maLibrariesDir);
1772         }
1773         return;
1774     }
1775 
1776     if ( bStorage )
1777     {
1778         // Don't write if only empty standard lib exists
1779         if ( ( nLibsToSave == 1 ) && ( aNames[0] == "Standard" ) )
1780         {
1781             Any aLibAny = maNameContainer->getByName( aNames[0] );
1782             Reference< XNameAccess > xNameAccess;
1783             aLibAny >>= xNameAccess;
1784             if ( ! xNameAccess->hasElements() )
1785             {
1786                 if ( bInplaceStorage && mxStorage->hasByName(maLibrariesDir) )
1787                 {
1788                     mxStorage->removeElement(maLibrariesDir);
1789                 }
1790                 return;
1791             }
1792         }
1793 
1794         // create the empty target storage
1795         try
1796         {
1797             OUString sTargetLibrariesStoreName;
1798             if ( bInplaceStorage )
1799             {
1800                 // create a temporary target storage
1801                 const OUStringBuffer aTempTargetNameBase = maLibrariesDir + "_temp_";
1802                 sal_Int32 index = 0;
1803                 do
1804                 {
1805                     OUStringBuffer aTempTargetName( aTempTargetNameBase );
1806                     aTempTargetName.append( index++ );
1807 
1808                     sTargetLibrariesStoreName = aTempTargetName.makeStringAndClear();
1809                     if ( !i_rStorage->hasByName( sTargetLibrariesStoreName ) )
1810                     {
1811                         break;
1812                     }
1813                 }
1814                 while ( true );
1815                 sTempTargetStorName = sTargetLibrariesStoreName;
1816             }
1817             else
1818             {
1819                 sTargetLibrariesStoreName = maLibrariesDir;
1820                 if ( i_rStorage->hasByName( sTargetLibrariesStoreName ) )
1821                 {
1822                     i_rStorage->removeElement( sTargetLibrariesStoreName );
1823                 }
1824             }
1825 
1826             xTargetLibrariesStor.set( i_rStorage->openStorageElement( sTargetLibrariesStoreName, embed::ElementModes::READWRITE ), UNO_QUERY_THROW );
1827         }
1828         catch( const uno::Exception& )
1829         {
1830             DBG_UNHANDLED_EXCEPTION("basic");
1831             return;
1832         }
1833 
1834         // open the source storage which might be used to copy yet-unmodified libraries
1835         try
1836         {
1837             if ( mxStorage->hasByName( maLibrariesDir ) || bInplaceStorage )
1838             {
1839                 xSourceLibrariesStor = mxStorage->openStorageElement( maLibrariesDir,
1840                                                    bInplaceStorage ? embed::ElementModes::READWRITE : embed::ElementModes::READ );
1841             }
1842         }
1843         catch( const uno::Exception& )
1844         {
1845             DBG_UNHANDLED_EXCEPTION("basic");
1846             return;
1847         }
1848     }
1849 
1850     int iArray = 0;
1851     pName = aNames.getConstArray();
1852     ::xmlscript::LibDescriptor aLibDescriptorForExtensionLibs;
1853     std::unique_ptr< ::xmlscript::LibDescriptorArray > pLibArray(new ::xmlscript::LibDescriptorArray(nLibsToSave));
1854     for( ; pName != pNamesEnd; ++pName )
1855     {
1856         SfxLibrary* pImplLib = getImplLib( *pName );
1857         if( pImplLib->mbSharedIndexFile )
1858         {
1859             continue;
1860         }
1861         const bool bExtensionLib = pImplLib->mbExtension;
1862         ::xmlscript::LibDescriptor& rLib = bExtensionLib ?
1863               aLibDescriptorForExtensionLibs : pLibArray->mpLibs[iArray];
1864         if( !bExtensionLib )
1865         {
1866             iArray++;
1867         }
1868         rLib.aName = *pName;
1869 
1870         rLib.bLink = pImplLib->mbLink;
1871         if( !bStorage || pImplLib->mbLink )
1872         {
1873             rLib.aStorageURL = ( pImplLib->maUnexpandedStorageURL.getLength() ) ?
1874                 pImplLib->maUnexpandedStorageURL : pImplLib->maLibInfoFileURL;
1875         }
1876         rLib.bReadOnly = pImplLib->mbReadOnly;
1877         rLib.bPreload = pImplLib->mbPreload;
1878         rLib.bPasswordProtected = pImplLib->mbPasswordProtected;
1879         rLib.aElementNames = pImplLib->getElementNames();
1880 
1881         if( pImplLib->implIsModified() || bComplete )
1882         {
1883 // Testing pImplLib->implIsModified() is not reliable,
1884 // IMHO the value of pImplLib->implIsModified() should
1885 // reflect whether the library ( in-memory ) model
1886 // is in sync with the library container's own storage. Currently
1887 // whenever the library model is written to *any* storage
1888 // pImplLib->implSetModified( sal_False ) is called
1889 // The way the code works, especially the way that sfx uses
1890 // temp storage when saving ( and later sets the root storage of the
1891 // library container ) and similar madness in dbaccess means some surgery
1892 // is required to make it possible to successfully use this optimisation
1893 // It would be possible to do the implSetModified() call below only
1894 // conditionally, but that would require an additional boolean to be
1895 // passed in via the XStorageBasedDocument::storeLibrariesToStorage()...
1896 // fdo#68983: If there's a password and the password is not known, only
1897 // copying the storage works!
1898             // Can we simply copy the storage?
1899             bool isCopyStorage = !mbOldInfoFormat && !mbOasis2OOoFormat
1900                     && !pImplLib->isLoadedStorable()
1901                     && xSourceLibrariesStor.is() /* null for user profile */;
1902             if (isCopyStorage)
1903             {
1904                 try
1905                 {
1906                     (void)xSourceLibrariesStor->isStorageElement(rLib.aName);
1907                 }
1908                 catch (container::NoSuchElementException const&)
1909                 {
1910                     isCopyStorage = false;
1911                 }
1912             }
1913             if (isCopyStorage)
1914             {
1915                 try
1916                 {
1917                     xSourceLibrariesStor->copyElementTo( rLib.aName, xTargetLibrariesStor, rLib.aName );
1918                 }
1919                 catch( const uno::Exception& )
1920                 {
1921                     DBG_UNHANDLED_EXCEPTION("basic");
1922                     // TODO: error handling?
1923                 }
1924             }
1925             else
1926             {
1927                 uno::Reference< embed::XStorage > xLibraryStor;
1928                 if( bStorage )
1929                 {
1930 #if OSL_DEBUG_LEVEL > 0
1931                     try
1932                     {
1933 #endif
1934                         xLibraryStor = xTargetLibrariesStor->openStorageElement(
1935                                                                         rLib.aName,
1936                                                                         embed::ElementModes::READWRITE );
1937 #if OSL_DEBUG_LEVEL > 0
1938                     }
1939                     catch(const uno::Exception& )
1940                     {
1941                         Any aError( ::cppu::getCaughtException() );
1942                         SAL_WARN(
1943                             "basic",
1944                             "couldn't create sub storage for library \""
1945                                 << rLib.aName << "\". Exception: "
1946                                 << comphelper::anyToString(aError));
1947                         throw;
1948                     }
1949 #endif
1950                 }
1951 
1952                 // Maybe lib is not loaded?!
1953                 if( bComplete )
1954                 {
1955                     loadLibrary( rLib.aName );
1956                 }
1957                 if( pImplLib->mbPasswordProtected )
1958                 {
1959                     implStorePasswordLibrary( pImplLib, rLib.aName, xLibraryStor, uno::Reference< task::XInteractionHandler >() );
1960                     // TODO: Check return value
1961                 }
1962                 else
1963                 {
1964                     implStoreLibrary( pImplLib, rLib.aName, xLibraryStor );
1965                 }
1966                 implStoreLibraryIndexFile( pImplLib, rLib, xLibraryStor );
1967                 if( bStorage )
1968                 {
1969                     try
1970                     {
1971                         uno::Reference< embed::XTransactedObject > xTransact( xLibraryStor, uno::UNO_QUERY_THROW );
1972                         xTransact->commit();
1973                     }
1974                     catch(const uno::Exception& )
1975                     {
1976                         DBG_UNHANDLED_EXCEPTION("basic");
1977                         // TODO: error handling
1978                         throw;
1979                     }
1980                 }
1981             }
1982             maModifiable.setModified( true );
1983             pImplLib->implSetModified( false );
1984         }
1985 
1986         // For container info ReadOnly refers to mbReadOnlyLink
1987         rLib.bReadOnly = pImplLib->mbReadOnlyLink;
1988     }
1989 
1990     // if we did an in-place save into a storage (i.e. a save into the storage we were already based on),
1991     // then we need to clean up the temporary storage we used for this
1992     if ( bInplaceStorage && !sTempTargetStorName.isEmpty() )
1993     {
1994         SAL_WARN_IF(
1995             !xSourceLibrariesStor.is(), "basic",
1996             ("SfxLibrariesContainer::storeLibraries_impl: unexpected: we should"
1997              " have a source storage here!"));
1998         try
1999         {
2000             // for this, we first remove everything from the source storage, then copy the complete content
2001             // from the temporary target storage. From then on, what used to be the "source storage" becomes
2002             // the "target storage" for all subsequent operations.
2003 
2004             // (We cannot simply remove the storage, denoted by maLibrariesDir, from i_rStorage - there might be
2005             // open references to it.)
2006 
2007             if ( xSourceLibrariesStor.is() )
2008             {
2009                 // remove
2010                 const Sequence< OUString > aRemoveNames( xSourceLibrariesStor->getElementNames() );
2011                 for ( auto const & removeName : aRemoveNames )
2012                 {
2013                     xSourceLibrariesStor->removeElement( removeName );
2014                 }
2015 
2016                 // copy
2017                 const Sequence< OUString > aCopyNames( xTargetLibrariesStor->getElementNames() );
2018                 for ( auto const & copyName : aCopyNames )
2019                 {
2020                     xTargetLibrariesStor->copyElementTo( copyName, xSourceLibrariesStor, copyName );
2021                 }
2022             }
2023 
2024             // close and remove temp target
2025             xTargetLibrariesStor->dispose();
2026             i_rStorage->removeElement( sTempTargetStorName );
2027             xTargetLibrariesStor.clear();
2028             sTempTargetStorName.clear();
2029 
2030             // adjust target
2031             xTargetLibrariesStor = xSourceLibrariesStor;
2032             xSourceLibrariesStor.clear();
2033         }
2034         catch( const Exception& )
2035         {
2036             DBG_UNHANDLED_EXCEPTION("basic");
2037             throw;
2038         }
2039     }
2040 
2041     if( !mbOldInfoFormat && !maModifiable.isModified() )
2042     {
2043         return;
2044     }
2045     maModifiable.setModified( false );
2046     mbOldInfoFormat = false;
2047 
2048     // Write library container info
2049     // Create sax writer
2050     Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
2051 
2052     // Write info file
2053     uno::Reference< io::XOutputStream > xOut;
2054     uno::Reference< io::XStream > xInfoStream;
2055     if( bStorage )
2056     {
2057         OUString aStreamName = maInfoFileName + "-lc.xml";
2058 
2059         try
2060         {
2061             xInfoStream = xTargetLibrariesStor->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
2062             uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY_THROW );
2063             xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
2064 
2065             // #87671 Allow encryption
2066             xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
2067 
2068             xOut = xInfoStream->getOutputStream();
2069         }
2070         catch(const uno::Exception& )
2071         {
2072             ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
2073         }
2074     }
2075     else
2076     {
2077         // Create Output stream
2078         INetURLObject aLibInfoInetObj( maLibraryPath.getToken(1, ';') );
2079         aLibInfoInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
2080         aLibInfoInetObj.setExtension( "xlc" );
2081         OUString aLibInfoPath( aLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2082 
2083         try
2084         {
2085             if( mxSFI->exists( aLibInfoPath ) )
2086             {
2087                 mxSFI->kill( aLibInfoPath );
2088             }
2089             xOut = mxSFI->openFileWrite( aLibInfoPath );
2090         }
2091         catch(const Exception& )
2092         {
2093             xOut.clear();
2094             SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
2095             ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
2096         }
2097 
2098     }
2099     if( !xOut.is() )
2100     {
2101         SAL_WARN("basic", "couldn't open output stream");
2102         return;
2103     }
2104 
2105     xWriter->setOutputStream( xOut );
2106 
2107     try
2108     {
2109         xmlscript::exportLibraryContainer( xWriter, pLibArray.get() );
2110         if ( bStorage )
2111         {
2112             uno::Reference< embed::XTransactedObject > xTransact( xTargetLibrariesStor, uno::UNO_QUERY_THROW );
2113             xTransact->commit();
2114         }
2115     }
2116     catch(const uno::Exception& )
2117     {
2118         SAL_WARN("basic", "Problem during storing of libraries!");
2119         ErrorHandler::HandleError(  ERRCODE_IO_GENERAL );
2120     }
2121 }
2122 
2123 
2124 // Methods XElementAccess
2125 Type SAL_CALL SfxLibraryContainer::getElementType()
2126 {
2127     LibraryContainerMethodGuard aGuard( *this );
2128     return maNameContainer->getElementType();
2129 }
2130 
2131 sal_Bool SfxLibraryContainer::hasElements()
2132 {
2133     LibraryContainerMethodGuard aGuard( *this );
2134     bool bRet = maNameContainer->hasElements();
2135     return bRet;
2136 }
2137 
2138 // Methods XNameAccess
2139 Any SfxLibraryContainer::getByName( const OUString& aName )
2140 {
2141     LibraryContainerMethodGuard aGuard( *this );
2142     Any aRetAny = maNameContainer->getByName( aName ) ;
2143     return aRetAny;
2144 }
2145 
2146 Sequence< OUString > SfxLibraryContainer::getElementNames()
2147 {
2148     LibraryContainerMethodGuard aGuard( *this );
2149     return maNameContainer->getElementNames();
2150 }
2151 
2152 sal_Bool SfxLibraryContainer::hasByName( const OUString& aName )
2153 {
2154     LibraryContainerMethodGuard aGuard( *this );
2155     return maNameContainer->hasByName( aName ) ;
2156 }
2157 
2158 // Methods XLibraryContainer
2159 Reference< XNameContainer > SAL_CALL SfxLibraryContainer::createLibrary( const OUString& Name )
2160 {
2161     LibraryContainerMethodGuard aGuard( *this );
2162     SfxLibrary* pNewLib = implCreateLibrary( Name );
2163     pNewLib->maLibElementFileExtension = maLibElementFileExtension;
2164 
2165     createVariableURL( pNewLib->maUnexpandedStorageURL, Name, maInfoFileName, true );
2166 
2167     Reference< XNameAccess > xNameAccess = static_cast< XNameAccess* >( pNewLib );
2168     Any aElement;
2169     aElement <<= xNameAccess;
2170     maNameContainer->insertByName( Name, aElement );
2171     maModifiable.setModified( true );
2172     Reference< XNameContainer > xRet( xNameAccess, UNO_QUERY );
2173     return xRet;
2174 }
2175 
2176 Reference< XNameAccess > SAL_CALL SfxLibraryContainer::createLibraryLink
2177     ( const OUString& Name, const OUString& StorageURL, sal_Bool ReadOnly )
2178 {
2179     LibraryContainerMethodGuard aGuard( *this );
2180     // TODO: Check other reasons to force ReadOnly status
2181     //if( !ReadOnly )
2182     //{
2183     //}
2184 
2185     OUString aLibInfoFileURL;
2186     OUString aLibDirURL;
2187     OUString aUnexpandedStorageURL;
2188     checkStorageURL( StorageURL, aLibInfoFileURL, aLibDirURL, aUnexpandedStorageURL );
2189 
2190 
2191     SfxLibrary* pNewLib = implCreateLibraryLink( Name, aLibInfoFileURL, aLibDirURL, ReadOnly );
2192     pNewLib->maLibElementFileExtension = maLibElementFileExtension;
2193     pNewLib->maUnexpandedStorageURL = aUnexpandedStorageURL;
2194     pNewLib->maOriginalStorageURL = StorageURL;
2195 
2196     uno::Reference< embed::XStorage > xDummyStor;
2197     ::xmlscript::LibDescriptor aLibDesc;
2198     implLoadLibraryIndexFile( pNewLib, aLibDesc, xDummyStor, OUString() );
2199     implImportLibDescriptor( pNewLib, aLibDesc );
2200 
2201     Reference< XNameAccess > xRet = static_cast< XNameAccess* >( pNewLib );
2202     Any aElement;
2203     aElement <<= xRet;
2204     maNameContainer->insertByName( Name, aElement );
2205     maModifiable.setModified( true );
2206 
2207     if( StorageURL.indexOf( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE" ) != -1 )
2208     {
2209         pNewLib->mbExtension = true;
2210     }
2211     else if( StorageURL.indexOf( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" ) != -1
2212            || StorageURL.indexOf( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" ) != -1 )
2213     {
2214         pNewLib->mbExtension = true;
2215         pNewLib->mbReadOnly = true;
2216     }
2217 
2218     return xRet;
2219 }
2220 
2221 void SAL_CALL SfxLibraryContainer::removeLibrary( const OUString& Name )
2222 {
2223     LibraryContainerMethodGuard aGuard( *this );
2224     // Get and hold library before removing
2225     Any aLibAny = maNameContainer->getByName( Name ) ;
2226     Reference< XNameAccess > xNameAccess;
2227     aLibAny >>= xNameAccess;
2228     SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
2229     if( pImplLib->mbReadOnly && !pImplLib->mbLink )
2230     {
2231         throw IllegalArgumentException();
2232     }
2233     // Remove from container
2234     maNameContainer->removeByName( Name );
2235     maModifiable.setModified( true );
2236 
2237     // Delete library files, but not for linked libraries
2238     if( !pImplLib->mbLink )
2239     {
2240         if( mxStorage.is() )
2241         {
2242             return;
2243         }
2244         if( xNameAccess->hasElements() )
2245         {
2246             Sequence< OUString > aNames = pImplLib->getElementNames();
2247             sal_Int32 nNameCount = aNames.getLength();
2248             const OUString* pNames = aNames.getConstArray();
2249             for( sal_Int32 i = 0 ; i < nNameCount ; ++i, ++pNames )
2250             {
2251                 pImplLib->removeElementWithoutChecks( *pNames, SfxLibrary::LibraryContainerAccess() );
2252             }
2253         }
2254 
2255         // Delete index file
2256         createAppLibraryFolder( pImplLib, Name );
2257         OUString aLibInfoPath = pImplLib->maLibInfoFileURL;
2258         try
2259         {
2260             if( mxSFI->exists( aLibInfoPath ) )
2261             {
2262                 mxSFI->kill( aLibInfoPath );
2263             }
2264         }
2265         catch(const Exception& ) {}
2266 
2267         // Delete folder if empty
2268         INetURLObject aInetObj( maLibraryPath.getToken(1, ';') );
2269         aInetObj.insertName( Name, true, INetURLObject::LAST_SEGMENT,
2270                              INetURLObject::EncodeMechanism::All );
2271         OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2272 
2273         try
2274         {
2275             if( mxSFI->isFolder( aLibDirPath ) )
2276             {
2277                 Sequence< OUString > aContentSeq = mxSFI->getFolderContents( aLibDirPath, true );
2278                 sal_Int32 nCount = aContentSeq.getLength();
2279                 if( !nCount )
2280                 {
2281                     mxSFI->kill( aLibDirPath );
2282                 }
2283             }
2284         }
2285         catch(const Exception& )
2286         {
2287         }
2288     }
2289 }
2290 
2291 sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLoaded( const OUString& Name )
2292 {
2293     LibraryContainerMethodGuard aGuard( *this );
2294     SfxLibrary* pImplLib = getImplLib( Name );
2295     bool bRet = pImplLib->mbLoaded;
2296     return bRet;
2297 }
2298 
2299 
2300 void SAL_CALL SfxLibraryContainer::loadLibrary( const OUString& Name )
2301 {
2302     LibraryContainerMethodGuard aGuard( *this );
2303     Any aLibAny = maNameContainer->getByName( Name ) ;
2304     Reference< XNameAccess > xNameAccess;
2305     aLibAny >>= xNameAccess;
2306     SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
2307 
2308     bool bLoaded = pImplLib->mbLoaded;
2309     pImplLib->mbLoaded = true;
2310     if( !bLoaded && xNameAccess->hasElements() )
2311     {
2312         if( pImplLib->mbPasswordProtected )
2313         {
2314             implLoadPasswordLibrary( pImplLib, Name );
2315             return;
2316         }
2317 
2318         bool bLink = pImplLib->mbLink;
2319         bool bStorage = mxStorage.is() && !bLink;
2320 
2321         uno::Reference< embed::XStorage > xLibrariesStor;
2322         uno::Reference< embed::XStorage > xLibraryStor;
2323         if( bStorage )
2324         {
2325 #if OSL_DEBUG_LEVEL > 0
2326             try
2327             {
2328 #endif
2329                 xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
2330                 SAL_WARN_IF(
2331                     !xLibrariesStor.is(), "basic",
2332                     ("The method must either throw exception or return a"
2333                      " storage!"));
2334                 if ( !xLibrariesStor.is() )
2335                 {
2336                     throw uno::RuntimeException("null returned from openStorageElement");
2337                 }
2338 
2339                 xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
2340                 SAL_WARN_IF(
2341                     !xLibraryStor.is(), "basic",
2342                     ("The method must either throw exception or return a"
2343                      " storage!"));
2344                 if ( !xLibrariesStor.is() )
2345                 {
2346                     throw uno::RuntimeException("null returned from openStorageElement");
2347                 }
2348 #if OSL_DEBUG_LEVEL > 0
2349             }
2350             catch(const uno::Exception& )
2351             {
2352                 Any aError( ::cppu::getCaughtException() );
2353                 SAL_WARN(
2354                     "basic",
2355                     "couldn't open sub storage for library \"" << Name
2356                         << "\". Exception: "
2357                         << comphelper::anyToString(aError));
2358                 throw;
2359             }
2360 #endif
2361         }
2362 
2363         Sequence< OUString > aNames = pImplLib->getElementNames();
2364         sal_Int32 nNameCount = aNames.getLength();
2365         const OUString* pNames = aNames.getConstArray();
2366         for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
2367         {
2368             OUString aElementName = pNames[ i ];
2369 
2370             OUString aFile;
2371             uno::Reference< io::XInputStream > xInStream;
2372 
2373             if( bStorage )
2374             {
2375                 uno::Reference< io::XStream > xElementStream;
2376 
2377                 aFile = aElementName + ".xml";
2378 
2379                 try
2380                 {
2381                     xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
2382                 }
2383                 catch(const uno::Exception& )
2384                 {}
2385 
2386                 if( !xElementStream.is() )
2387                 {
2388                     // Check for EA2 document version with wrong extensions
2389                     aFile = aElementName + "." + maLibElementFileExtension;
2390                     try
2391                     {
2392                         xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
2393                     }
2394                     catch(const uno::Exception& )
2395                     {}
2396                 }
2397 
2398                 if ( xElementStream.is() )
2399                 {
2400                     xInStream = xElementStream->getInputStream();
2401                 }
2402                 if ( !xInStream.is() )
2403                 {
2404                     SAL_WARN(
2405                         "basic",
2406                         "couldn't open library element stream - attempted to"
2407                             " open library \"" << Name << '"');
2408                     throw RuntimeException("couldn't open library element stream", *this);
2409                 }
2410             }
2411             else
2412             {
2413                 OUString aLibDirPath = pImplLib->maStorageURL;
2414                 INetURLObject aElementInetObj( aLibDirPath );
2415                 aElementInetObj.insertName( aElementName, false,
2416                                             INetURLObject::LAST_SEGMENT,
2417                                             INetURLObject::EncodeMechanism::All );
2418                 aElementInetObj.setExtension( maLibElementFileExtension );
2419                 aFile = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2420             }
2421 
2422             Reference< XNameContainer > xLib( pImplLib );
2423             Any aAny = importLibraryElement( xLib, aElementName,
2424                                              aFile, xInStream );
2425             if( pImplLib->hasByName( aElementName ) )
2426             {
2427                 if( aAny.hasValue() )
2428                 {
2429                     pImplLib->maNameContainer->replaceByName( aElementName, aAny );
2430                 }
2431             }
2432             else
2433             {
2434                 pImplLib->maNameContainer->insertNoCheck(aElementName, aAny);
2435             }
2436         }
2437         pImplLib->implSetModified( false );
2438     }
2439 }
2440 
2441 // Methods XLibraryContainer2
2442 sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLink( const OUString& Name )
2443 {
2444     LibraryContainerMethodGuard aGuard( *this );
2445     SfxLibrary* pImplLib = getImplLib( Name );
2446     bool bRet = pImplLib->mbLink;
2447     return bRet;
2448 }
2449 
2450 OUString SAL_CALL SfxLibraryContainer::getLibraryLinkURL( const OUString& Name )
2451 {
2452     LibraryContainerMethodGuard aGuard( *this );
2453     SfxLibrary* pImplLib = getImplLib( Name );
2454     bool bLink = pImplLib->mbLink;
2455     if( !bLink )
2456     {
2457         throw IllegalArgumentException();
2458     }
2459     OUString aRetStr = pImplLib->maLibInfoFileURL;
2460     return aRetStr;
2461 }
2462 
2463 sal_Bool SAL_CALL SfxLibraryContainer::isLibraryReadOnly( const OUString& Name )
2464 {
2465     LibraryContainerMethodGuard aGuard( *this );
2466     SfxLibrary* pImplLib = getImplLib( Name );
2467     bool bRet = pImplLib->mbReadOnly || (pImplLib->mbLink && pImplLib->mbReadOnlyLink);
2468     return bRet;
2469 }
2470 
2471 void SAL_CALL SfxLibraryContainer::setLibraryReadOnly( const OUString& Name, sal_Bool bReadOnly )
2472 {
2473     LibraryContainerMethodGuard aGuard( *this );
2474     SfxLibrary* pImplLib = getImplLib( Name );
2475     if( pImplLib->mbLink )
2476     {
2477         if( pImplLib->mbReadOnlyLink != bool(bReadOnly) )
2478         {
2479             pImplLib->mbReadOnlyLink = bReadOnly;
2480             pImplLib->implSetModified( true );
2481             maModifiable.setModified( true );
2482         }
2483     }
2484     else
2485     {
2486         if( pImplLib->mbReadOnly != bool(bReadOnly) )
2487         {
2488             pImplLib->mbReadOnly = bReadOnly;
2489             pImplLib->implSetModified( true );
2490         }
2491     }
2492 }
2493 
2494 void SAL_CALL SfxLibraryContainer::renameLibrary( const OUString& Name, const OUString& NewName )
2495 {
2496     LibraryContainerMethodGuard aGuard( *this );
2497     if( maNameContainer->hasByName( NewName ) )
2498     {
2499         throw ElementExistException();
2500     }
2501     // Get and hold library before removing
2502     Any aLibAny = maNameContainer->getByName( Name ) ;
2503 
2504     // #i24094 Maybe lib is not loaded!
2505     Reference< XNameAccess > xNameAccess;
2506     aLibAny >>= xNameAccess;
2507     SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
2508     if( pImplLib->mbPasswordProtected && !pImplLib->mbPasswordVerified )
2509     {
2510         return;     // Lib with unverified password cannot be renamed
2511     }
2512     loadLibrary( Name );
2513 
2514     // Remove from container
2515     maNameContainer->removeByName( Name );
2516     maModifiable.setModified( true );
2517 
2518     // Rename library folder, but not for linked libraries
2519     bool bMovedSuccessful = true;
2520 
2521     // Rename files
2522     bool bStorage = mxStorage.is();
2523     if( !bStorage && !pImplLib->mbLink )
2524     {
2525         bMovedSuccessful = false;
2526 
2527         OUString aLibDirPath = pImplLib->maStorageURL;
2528 
2529         INetURLObject aDestInetObj( maLibraryPath.getToken(1, ';'));
2530         aDestInetObj.insertName( NewName, true, INetURLObject::LAST_SEGMENT,
2531                                  INetURLObject::EncodeMechanism::All );
2532         OUString aDestDirPath = aDestInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2533 
2534         // Store new URL
2535         OUString aLibInfoFileURL = pImplLib->maLibInfoFileURL;
2536         checkStorageURL( aDestDirPath, pImplLib->maLibInfoFileURL, pImplLib->maStorageURL,
2537                          pImplLib->maUnexpandedStorageURL );
2538 
2539         try
2540         {
2541             if( mxSFI->isFolder( aLibDirPath ) )
2542             {
2543                 if( !mxSFI->isFolder( aDestDirPath ) )
2544                 {
2545                     mxSFI->createFolder( aDestDirPath );
2546                 }
2547                 // Move index file
2548                 try
2549                 {
2550                     if( mxSFI->exists( pImplLib->maLibInfoFileURL ) )
2551                     {
2552                         mxSFI->kill( pImplLib->maLibInfoFileURL );
2553                     }
2554                     mxSFI->move( aLibInfoFileURL, pImplLib->maLibInfoFileURL );
2555                 }
2556                 catch(const Exception& )
2557                 {
2558                 }
2559 
2560                 Sequence< OUString > aElementNames = xNameAccess->getElementNames();
2561                 sal_Int32 nNameCount = aElementNames.getLength();
2562                 const OUString* pNames = aElementNames.getConstArray();
2563                 for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
2564                 {
2565                     OUString aElementName = pNames[ i ];
2566 
2567                     INetURLObject aElementInetObj( aLibDirPath );
2568                     aElementInetObj.insertName( aElementName, false,
2569                         INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
2570                     aElementInetObj.setExtension( maLibElementFileExtension );
2571                     OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2572 
2573                     INetURLObject aElementDestInetObj( aDestDirPath );
2574                     aElementDestInetObj.insertName( aElementName, false,
2575                                                     INetURLObject::LAST_SEGMENT,
2576                                                     INetURLObject::EncodeMechanism::All );
2577                     aElementDestInetObj.setExtension( maLibElementFileExtension );
2578                     OUString aDestElementPath( aElementDestInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
2579 
2580                     try
2581                     {
2582                         if( mxSFI->exists( aDestElementPath ) )
2583                         {
2584                             mxSFI->kill( aDestElementPath );
2585                         }
2586                         mxSFI->move( aElementPath, aDestElementPath );
2587                     }
2588                     catch(const Exception& )
2589                     {
2590                     }
2591                 }
2592                 pImplLib->storeResourcesAsURL( aDestDirPath, NewName );
2593 
2594                 // Delete folder if empty
2595                 Sequence< OUString > aContentSeq = mxSFI->getFolderContents( aLibDirPath, true );
2596                 sal_Int32 nCount = aContentSeq.getLength();
2597                 if( !nCount )
2598                 {
2599                     mxSFI->kill( aLibDirPath );
2600                 }
2601 
2602                 bMovedSuccessful = true;
2603                 pImplLib->implSetModified( true );
2604             }
2605         }
2606         catch(const Exception& )
2607         {
2608             // Restore old library
2609             maNameContainer->insertByName( Name, aLibAny ) ;
2610         }
2611     }
2612 
2613     if( bStorage && !pImplLib->mbLink )
2614     {
2615         pImplLib->implSetModified( true );
2616     }
2617     if( bMovedSuccessful )
2618     {
2619            maNameContainer->insertByName( NewName, aLibAny ) ;
2620     }
2621 }
2622 
2623 
2624 // Methods XInitialization
2625 void SAL_CALL SfxLibraryContainer::initialize( const Sequence< Any >& _rArguments )
2626 {
2627     LibraryContainerMethodGuard aGuard( *this );
2628     sal_Int32 nArgCount = _rArguments.getLength();
2629     if ( nArgCount == 1 )
2630     {
2631         OUString sInitialDocumentURL;
2632         Reference< XStorageBasedDocument > xDocument;
2633         if ( _rArguments[0] >>= sInitialDocumentURL )
2634         {
2635             init( sInitialDocumentURL, nullptr );
2636             return;
2637         }
2638 
2639         if ( _rArguments[0] >>= xDocument )
2640         {
2641             initializeFromDocument( xDocument );
2642             return;
2643         }
2644     }
2645 
2646     throw IllegalArgumentException();
2647 }
2648 
2649 void SfxLibraryContainer::initializeFromDocument( const Reference< XStorageBasedDocument >& _rxDocument )
2650 {
2651     // check whether this is a valid OfficeDocument, and obtain the document's root storage
2652     Reference< XStorage > xDocStorage;
2653     try
2654     {
2655         Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY_THROW );
2656         if ( xSI->supportsService("com.sun.star.document.OfficeDocument"))
2657         {
2658             xDocStorage.set( _rxDocument->getDocumentStorage(), UNO_QUERY_THROW );
2659         }
2660         Reference< XModel > xDocument( _rxDocument, UNO_QUERY_THROW );
2661         Reference< XComponent > xDocComponent( _rxDocument, UNO_QUERY_THROW );
2662 
2663         mxOwnerDocument = xDocument;
2664         startComponentListening( xDocComponent );
2665     }
2666     catch( const Exception& ) { }
2667 
2668     if ( !xDocStorage.is() )
2669     {
2670         throw IllegalArgumentException();
2671     }
2672     init( OUString(), xDocStorage );
2673 }
2674 
2675 // OEventListenerAdapter
2676 void SfxLibraryContainer::_disposing( const EventObject& _rSource )
2677 {
2678 #if OSL_DEBUG_LEVEL > 0
2679     Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
2680     SAL_WARN_IF(
2681         xDocument != _rSource.Source || !xDocument.is(), "basic",
2682         "SfxLibraryContainer::_disposing: where does this come from?");
2683 #else
2684     (void)_rSource;
2685 #endif
2686     dispose();
2687 }
2688 
2689 // OComponentHelper
2690 void SAL_CALL SfxLibraryContainer::disposing()
2691 {
2692     Reference< XModel > xModel = mxOwnerDocument;
2693     EventObject aEvent( xModel.get() );
2694     maVBAScriptListeners.disposing( aEvent );
2695     stopAllComponentListening();
2696     mxOwnerDocument.clear();
2697 }
2698 
2699 // Methods XLibraryContainerPassword
2700 sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordProtected( const OUString& )
2701 {
2702     return false;
2703 }
2704 
2705 sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordVerified( const OUString& )
2706 {
2707     throw IllegalArgumentException();
2708 }
2709 
2710 sal_Bool SAL_CALL SfxLibraryContainer::verifyLibraryPassword( const OUString&, const OUString& )
2711 {
2712     throw IllegalArgumentException();
2713 }
2714 
2715 void SAL_CALL SfxLibraryContainer::changeLibraryPassword(const OUString&, const OUString&, const OUString& )
2716 {
2717     throw IllegalArgumentException();
2718 }
2719 
2720 // Methods XContainer
2721 void SAL_CALL SfxLibraryContainer::addContainerListener( const Reference< XContainerListener >& xListener )
2722 {
2723     LibraryContainerMethodGuard aGuard( *this );
2724     maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
2725     maNameContainer->addContainerListener( xListener );
2726 }
2727 
2728 void SAL_CALL SfxLibraryContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
2729 {
2730     LibraryContainerMethodGuard aGuard( *this );
2731     maNameContainer->removeContainerListener( xListener );
2732 }
2733 
2734 // Methods XLibraryContainerExport
2735 void SAL_CALL SfxLibraryContainer::exportLibrary( const OUString& Name, const OUString& URL,
2736     const Reference< XInteractionHandler >& Handler )
2737 {
2738     LibraryContainerMethodGuard aGuard( *this );
2739     SfxLibrary* pImplLib = getImplLib( Name );
2740 
2741     Reference< XSimpleFileAccess3 > xToUseSFI;
2742     if( Handler.is() )
2743     {
2744         xToUseSFI = ucb::SimpleFileAccess::create( mxContext );
2745         xToUseSFI->setInteractionHandler( Handler );
2746     }
2747 
2748     // Maybe lib is not loaded?!
2749     loadLibrary( Name );
2750 
2751     uno::Reference< css::embed::XStorage > xDummyStor;
2752     if( pImplLib->mbPasswordProtected )
2753     {
2754         implStorePasswordLibrary( pImplLib, Name, xDummyStor, URL, xToUseSFI, Handler );
2755     }
2756     else
2757     {
2758         implStoreLibrary( pImplLib, Name, xDummyStor, URL, xToUseSFI, Handler );
2759     }
2760     ::xmlscript::LibDescriptor aLibDesc;
2761     aLibDesc.aName = Name;
2762     aLibDesc.bLink = false;             // Link status gets lost?
2763     aLibDesc.bReadOnly = pImplLib->mbReadOnly;
2764     aLibDesc.bPreload = false;          // Preload status gets lost?
2765     aLibDesc.bPasswordProtected = pImplLib->mbPasswordProtected;
2766     aLibDesc.aElementNames = pImplLib->getElementNames();
2767 
2768     implStoreLibraryIndexFile( pImplLib, aLibDesc, xDummyStor, URL, xToUseSFI );
2769 }
2770 
2771 OUString SfxLibraryContainer::expand_url( const OUString& url )
2772 {
2773     if (url.startsWithIgnoreAsciiCase( "vnd.sun.star.expand:" ))
2774     {
2775         return comphelper::getExpandedUri(mxContext, url);
2776     }
2777     else if( mxStringSubstitution.is() )
2778     {
2779         OUString ret( mxStringSubstitution->substituteVariables( url, false ) );
2780         return ret;
2781     }
2782     else
2783     {
2784         return url;
2785     }
2786 }
2787 
2788 //XLibraryContainer3
2789 OUString SAL_CALL SfxLibraryContainer::getOriginalLibraryLinkURL( const OUString& Name )
2790 {
2791     LibraryContainerMethodGuard aGuard( *this );
2792     SfxLibrary* pImplLib = getImplLib( Name );
2793     bool bLink = pImplLib->mbLink;
2794     if( !bLink )
2795     {
2796         throw IllegalArgumentException();
2797     }
2798     OUString aRetStr = pImplLib->maOriginalStorageURL;
2799     return aRetStr;
2800 }
2801 
2802 
2803 // XVBACompatibility
2804 sal_Bool SAL_CALL SfxLibraryContainer::getVBACompatibilityMode()
2805 {
2806     return mbVBACompat;
2807 }
2808 
2809 void SAL_CALL SfxLibraryContainer::setVBACompatibilityMode( sal_Bool _vbacompatmodeon )
2810 {
2811     /*  The member variable mbVBACompat must be set first, the following call
2812         to getBasicManager() may call getVBACompatibilityMode() which returns
2813         this value. */
2814     mbVBACompat = _vbacompatmodeon;
2815     if( BasicManager* pBasMgr = getBasicManager() )
2816     {
2817         // get the standard library
2818         OUString aLibName = pBasMgr->GetName();
2819         if ( aLibName.isEmpty())
2820         {
2821             aLibName = "Standard";
2822         }
2823         if( StarBASIC* pBasic = pBasMgr->GetLib( aLibName ) )
2824         {
2825             pBasic->SetVBAEnabled( _vbacompatmodeon );
2826         }
2827         /*  If in VBA compatibility mode, force creation of the VBA Globals
2828             object. Each application will create an instance of its own
2829             implementation and store it in its Basic manager. Implementations
2830             will do all necessary additional initialization, such as
2831             registering the global "This***Doc" UNO constant, starting the
2832             document events processor etc.
2833          */
2834         if( mbVBACompat ) try
2835         {
2836             Reference< XModel > xModel( mxOwnerDocument );   // weak-ref -> ref
2837             Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
2838             xFactory->createInstance("ooo.vba.VBAGlobals");
2839         }
2840         catch(const Exception& )
2841         {
2842         }
2843     }
2844 }
2845 
2846 void SAL_CALL SfxLibraryContainer::setProjectName( const OUString& _projectname )
2847 {
2848     msProjectName = _projectname;
2849     BasicManager* pBasMgr = getBasicManager();
2850     // Temporary HACK
2851     // Some parts of the VBA handling ( e.g. in core basic )
2852     // code expect the name of the VBA project to be set as the name of
2853     // the basic manager. Provide fail back here.
2854     if( pBasMgr )
2855     {
2856         pBasMgr->SetName( msProjectName );
2857     }
2858 }
2859 
2860 sal_Int32 SAL_CALL SfxLibraryContainer::getRunningVBAScripts()
2861 {
2862     LibraryContainerMethodGuard aGuard( *this );
2863     return mnRunningVBAScripts;
2864 }
2865 
2866 void SAL_CALL SfxLibraryContainer::addVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener )
2867 {
2868     maVBAScriptListeners.addTypedListener( rxListener );
2869 }
2870 
2871 void SAL_CALL SfxLibraryContainer::removeVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener )
2872 {
2873     maVBAScriptListeners.removeTypedListener( rxListener );
2874 }
2875 
2876 void SAL_CALL SfxLibraryContainer::broadcastVBAScriptEvent( sal_Int32 nIdentifier, const OUString& rModuleName )
2877 {
2878     // own lock for accessing the number of running scripts
2879     enterMethod();
2880     switch( nIdentifier )
2881     {
2882     case vba::VBAScriptEventId::SCRIPT_STARTED:
2883         ++mnRunningVBAScripts;
2884         break;
2885     case vba::VBAScriptEventId::SCRIPT_STOPPED:
2886         --mnRunningVBAScripts;
2887         break;
2888     }
2889     leaveMethod();
2890 
2891     Reference< XModel > xModel = mxOwnerDocument;  // weak-ref -> ref
2892     vba::VBAScriptEvent aEvent( Reference<XInterface>(xModel, UNO_QUERY), nIdentifier, rModuleName );
2893     maVBAScriptListeners.notify( aEvent );
2894 }
2895 
2896 // Methods XServiceInfo
2897 sal_Bool SAL_CALL SfxLibraryContainer::supportsService( const OUString& _rServiceName )
2898 {
2899     return cppu::supportsService(this, _rServiceName);
2900 }
2901 
2902 // Implementation class SfxLibrary
2903 
2904 // Ctor
2905 SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
2906     const Reference< XSimpleFileAccess3 >& xSFI )
2907         : OComponentHelper( m_aMutex )
2908         , mxSFI( xSFI )
2909         , mrModifiable( _rModifiable )
2910         , maNameContainer( new NameContainer(aType) )
2911         , mbLoaded( true )
2912         , mbIsModified( true )
2913         , mbInitialised( false )
2914         , mbLink( false )
2915         , mbReadOnly( false )
2916         , mbReadOnlyLink( false )
2917         , mbPreload( false )
2918         , mbPasswordProtected( false )
2919         , mbPasswordVerified( false )
2920         , mbDoc50Password( false )
2921         , mbSharedIndexFile( false )
2922         , mbExtension( false )
2923 {
2924 }
2925 
2926 SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
2927     const Reference< XSimpleFileAccess3 >& xSFI,
2928     const OUString& aLibInfoFileURL, const OUString& aStorageURL, bool ReadOnly )
2929         : OComponentHelper( m_aMutex )
2930         , mxSFI( xSFI )
2931         , mrModifiable( _rModifiable )
2932         , maNameContainer( new NameContainer(aType) )
2933         , mbLoaded( false )
2934         , mbIsModified( true )
2935         , mbInitialised( false )
2936         , maLibInfoFileURL( aLibInfoFileURL )
2937         , maStorageURL( aStorageURL )
2938         , mbLink( true )
2939         , mbReadOnly( false )
2940         , mbReadOnlyLink( ReadOnly )
2941         , mbPreload( false )
2942         , mbPasswordProtected( false )
2943         , mbPasswordVerified( false )
2944         , mbDoc50Password( false )
2945         , mbSharedIndexFile( false )
2946         , mbExtension( false )
2947 {
2948 }
2949 
2950 bool SfxLibrary::isLoadedStorable()
2951 {
2952     return mbLoaded && (!mbPasswordProtected || mbPasswordVerified);
2953 }
2954 
2955 void SfxLibrary::implSetModified( bool _bIsModified )
2956 {
2957     if ( mbIsModified == _bIsModified )
2958     {
2959         return;
2960     }
2961     mbIsModified = _bIsModified;
2962     if ( mbIsModified )
2963     {
2964         mrModifiable.setModified( true );
2965     }
2966 }
2967 
2968 // Methods XInterface
2969 Any SAL_CALL SfxLibrary::queryInterface( const Type& rType )
2970 {
2971     Any aRet;
2972 
2973     aRet =
2974         ::cppu::queryInterface(
2975             rType,
2976             static_cast< XContainer * >( this ),
2977             static_cast< XNameContainer * >( this ),
2978             static_cast< XNameAccess * >( this ),
2979             static_cast< XElementAccess * >( this ),
2980             static_cast< XChangesNotifier * >( this ) );
2981     if( !aRet.hasValue() )
2982     {
2983         aRet = OComponentHelper::queryInterface( rType );
2984     }
2985     return aRet;
2986 }
2987 
2988 // Methods XElementAccess
2989 Type SfxLibrary::getElementType()
2990 {
2991     return maNameContainer->getElementType();
2992 }
2993 
2994 sal_Bool SfxLibrary::hasElements()
2995 {
2996     bool bRet = maNameContainer->hasElements();
2997     return bRet;
2998 }
2999 
3000 // Methods XNameAccess
3001 Any SfxLibrary::getByName( const OUString& aName )
3002 {
3003     impl_checkLoaded();
3004 
3005     Any aRetAny = maNameContainer->getByName( aName ) ;
3006     return aRetAny;
3007 }
3008 
3009 Sequence< OUString > SfxLibrary::getElementNames()
3010 {
3011     return maNameContainer->getElementNames();
3012 }
3013 
3014 sal_Bool SfxLibrary::hasByName( const OUString& aName )
3015 {
3016     bool bRet = maNameContainer->hasByName( aName );
3017     return bRet;
3018 }
3019 
3020 void SfxLibrary::impl_checkReadOnly()
3021 {
3022     if( mbReadOnly || (mbLink && mbReadOnlyLink) )
3023     {
3024         throw IllegalArgumentException(
3025             "Library is readonly.",
3026             // TODO: resource
3027             *this, 0
3028         );
3029     }
3030 }
3031 
3032 void SfxLibrary::impl_checkLoaded()
3033 {
3034     if ( !mbLoaded )
3035     {
3036         throw WrappedTargetException(
3037             OUString(),
3038             *this,
3039             Any( LibraryNotLoadedException(
3040                 OUString(),
3041                 *this
3042             ) )
3043         );
3044     }
3045 }
3046 
3047 // Methods XNameReplace
3048 void SfxLibrary::replaceByName( const OUString& aName, const Any& aElement )
3049 {
3050     impl_checkReadOnly();
3051     impl_checkLoaded();
3052 
3053     SAL_WARN_IF(
3054         !isLibraryElementValid(aElement), "basic",
3055         "SfxLibrary::replaceByName: replacing element is invalid!");
3056 
3057     maNameContainer->replaceByName( aName, aElement );
3058     implSetModified( true );
3059 }
3060 
3061 
3062 // Methods XNameContainer
3063 void SfxLibrary::insertByName( const OUString& aName, const Any& aElement )
3064 {
3065     impl_checkReadOnly();
3066     impl_checkLoaded();
3067 
3068     SAL_WARN_IF(
3069         !isLibraryElementValid(aElement), "basic",
3070         "SfxLibrary::insertByName: to-be-inserted element is invalid!");
3071 
3072     maNameContainer->insertByName( aName, aElement );
3073     implSetModified( true );
3074 }
3075 
3076 void SfxLibrary::impl_removeWithoutChecks( const OUString& _rElementName )
3077 {
3078     maNameContainer->removeByName( _rElementName );
3079     implSetModified( true );
3080 
3081     // Remove element file
3082     if( !maStorageURL.isEmpty() )
3083     {
3084         INetURLObject aElementInetObj( maStorageURL );
3085         aElementInetObj.insertName( _rElementName, false,
3086                                     INetURLObject::LAST_SEGMENT,
3087                                     INetURLObject::EncodeMechanism::All );
3088         aElementInetObj.setExtension( maLibElementFileExtension );
3089         OUString aFile = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3090 
3091         try
3092         {
3093             if( mxSFI->exists( aFile ) )
3094             {
3095                 mxSFI->kill( aFile );
3096             }
3097         }
3098         catch(const Exception& )
3099         {
3100             DBG_UNHANDLED_EXCEPTION("basic");
3101         }
3102     }
3103 }
3104 
3105 void SfxLibrary::removeByName( const OUString& Name )
3106 {
3107     impl_checkReadOnly();
3108     impl_checkLoaded();
3109     impl_removeWithoutChecks( Name );
3110 }
3111 
3112 // XTypeProvider
3113 Sequence< Type > SfxLibrary::getTypes()
3114 {
3115     static OTypeCollection ourTypes_NameContainer(
3116                 cppu::UnoType<XNameContainer>::get(),
3117                 cppu::UnoType<XContainer>::get(),
3118                 cppu::UnoType<XChangesNotifier>::get(),
3119                 OComponentHelper::getTypes() );
3120 
3121     return ourTypes_NameContainer.getTypes();
3122 }
3123 
3124 
3125 Sequence< sal_Int8 > SfxLibrary::getImplementationId()
3126 {
3127     return css::uno::Sequence<sal_Int8>();
3128 }
3129 
3130 // Methods XContainer
3131 void SAL_CALL SfxLibrary::addContainerListener( const Reference< XContainerListener >& xListener )
3132 {
3133     maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
3134     maNameContainer->addContainerListener( xListener );
3135 }
3136 
3137 void SAL_CALL SfxLibrary::removeContainerListener( const Reference< XContainerListener >& xListener )
3138 {
3139     maNameContainer->removeContainerListener( xListener );
3140 }
3141 
3142 // Methods XChangesNotifier
3143 void SAL_CALL SfxLibrary::addChangesListener( const Reference< XChangesListener >& xListener )
3144 {
3145     maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
3146     maNameContainer->addChangesListener( xListener );
3147 }
3148 
3149 void SAL_CALL SfxLibrary::removeChangesListener( const Reference< XChangesListener >& xListener )
3150 {
3151     maNameContainer->removeChangesListener( xListener );
3152 }
3153 
3154 
3155 // Implementation class ScriptExtensionIterator
3156 
3157 #define sBasicLibMediaType "application/vnd.sun.star.basic-library"
3158 #define sDialogLibMediaType "application/vnd.sun.star.dialog-library"
3159 
3160 ScriptExtensionIterator::ScriptExtensionIterator()
3161     : m_xContext( comphelper::getProcessComponentContext() )
3162     , m_eState( USER_EXTENSIONS )
3163     , m_bUserPackagesLoaded( false )
3164     , m_bSharedPackagesLoaded( false )
3165     , m_bBundledPackagesLoaded( false )
3166     , m_iUserPackage( 0 )
3167     , m_iSharedPackage( 0 )
3168        , m_iBundledPackage( 0 )
3169     , m_pScriptSubPackageIterator( nullptr )
3170 {}
3171 
3172 OUString ScriptExtensionIterator::nextBasicOrDialogLibrary( bool& rbPureDialogLib )
3173 {
3174     OUString aRetLib;
3175 
3176     while( aRetLib.isEmpty() && m_eState != END_REACHED )
3177     {
3178         switch( m_eState )
3179         {
3180             case USER_EXTENSIONS:
3181             {
3182                 Reference< deployment::XPackage > xScriptPackage =
3183                     implGetNextUserScriptPackage( rbPureDialogLib );
3184                 if( !xScriptPackage.is() )
3185                 {
3186                     break;
3187                 }
3188                 aRetLib = xScriptPackage->getURL();
3189                 break;
3190             }
3191 
3192             case SHARED_EXTENSIONS:
3193             {
3194                 Reference< deployment::XPackage > xScriptPackage =
3195                     implGetNextSharedScriptPackage( rbPureDialogLib );
3196                 if( !xScriptPackage.is() )
3197                 {
3198                     break;
3199                 }
3200                 aRetLib = xScriptPackage->getURL();
3201                 break;
3202             }
3203             case BUNDLED_EXTENSIONS:
3204             {
3205                 Reference< deployment::XPackage > xScriptPackage =
3206                     implGetNextBundledScriptPackage( rbPureDialogLib );
3207                 if( !xScriptPackage.is() )
3208                 {
3209                     break;
3210                 }
3211                 aRetLib = xScriptPackage->getURL();
3212                 break;
3213             }
3214             case END_REACHED:
3215                 SAL_WARN(
3216                     "basic",
3217                     ("ScriptExtensionIterator::nextBasicOrDialogLibrary():"
3218                      " Invalid case END_REACHED"));
3219                 break;
3220         }
3221     }
3222 
3223     return aRetLib;
3224 }
3225 
3226 ScriptSubPackageIterator::ScriptSubPackageIterator( Reference< deployment::XPackage > const & xMainPackage )
3227     : m_xMainPackage( xMainPackage )
3228     , m_bIsValid( false )
3229     , m_bIsBundle( false )
3230     , m_nSubPkgCount( 0 )
3231     , m_iNextSubPkg( 0 )
3232 {
3233     if( !m_xMainPackage.is() )
3234     {
3235         return;
3236     }
3237     // Check if parent package is registered
3238     beans::Optional< beans::Ambiguous<sal_Bool> > option( m_xMainPackage->isRegistered
3239         ( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
3240     bool bRegistered = false;
3241     if( option.IsPresent )
3242     {
3243         beans::Ambiguous<sal_Bool> const & reg = option.Value;
3244         if( !reg.IsAmbiguous && reg.Value )
3245         {
3246             bRegistered = true;
3247         }
3248     }
3249     if( bRegistered )
3250     {
3251         m_bIsValid = true;
3252         if( m_xMainPackage->isBundle() )
3253         {
3254             m_bIsBundle = true;
3255             m_aSubPkgSeq = m_xMainPackage->getBundle( Reference<task::XAbortChannel>(),
3256                                                       Reference<ucb::XCommandEnvironment>() );
3257             m_nSubPkgCount = m_aSubPkgSeq.getLength();
3258         }
3259     }
3260 }
3261 
3262 Reference< deployment::XPackage > ScriptSubPackageIterator::getNextScriptSubPackage( bool& rbPureDialogLib )
3263 {
3264     rbPureDialogLib = false;
3265 
3266     Reference< deployment::XPackage > xScriptPackage;
3267     if( !m_bIsValid )
3268     {
3269         return xScriptPackage;
3270     }
3271     if( m_bIsBundle )
3272     {
3273         const Reference< deployment::XPackage >* pSeq = m_aSubPkgSeq.getConstArray();
3274         sal_Int32 iPkg;
3275         for( iPkg = m_iNextSubPkg ; iPkg < m_nSubPkgCount ; ++iPkg )
3276         {
3277             const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
3278             xScriptPackage = implDetectScriptPackage( xSubPkg, rbPureDialogLib );
3279             if( xScriptPackage.is() )
3280             {
3281                 break;
3282             }
3283         }
3284         m_iNextSubPkg = iPkg + 1;
3285     }
3286     else
3287     {
3288         xScriptPackage = implDetectScriptPackage( m_xMainPackage, rbPureDialogLib );
3289         m_bIsValid = false;     // No more script packages
3290     }
3291 
3292     return xScriptPackage;
3293 }
3294 
3295 Reference< deployment::XPackage > ScriptSubPackageIterator::implDetectScriptPackage ( const Reference< deployment::XPackage >& rPackage,
3296                                                                                       bool& rbPureDialogLib )
3297 {
3298     Reference< deployment::XPackage > xScriptPackage;
3299 
3300     if( rPackage.is() )
3301     {
3302         const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = rPackage->getPackageType();
3303         OUString aMediaType = xPackageTypeInfo->getMediaType();
3304         if ( aMediaType == sBasicLibMediaType )
3305         {
3306             xScriptPackage = rPackage;
3307         }
3308         else if ( aMediaType == sDialogLibMediaType )
3309         {
3310             rbPureDialogLib = true;
3311             xScriptPackage = rPackage;
3312         }
3313     }
3314 
3315     return xScriptPackage;
3316 }
3317 
3318 Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextUserScriptPackage( bool& rbPureDialogLib )
3319 {
3320     Reference< deployment::XPackage > xScriptPackage;
3321 
3322     if( !m_bUserPackagesLoaded )
3323     {
3324         try
3325         {
3326             Reference< XExtensionManager > xManager = ExtensionManager::get( m_xContext );
3327             m_aUserPackagesSeq = xManager->getDeployedExtensions("user",
3328                                                                  Reference< task::XAbortChannel >(),
3329                                                                  Reference< ucb::XCommandEnvironment >() );
3330         }
3331         catch(const css::uno::DeploymentException& )
3332         {
3333             // Special Office installations may not contain deployment code
3334             m_eState = END_REACHED;
3335             return xScriptPackage;
3336         }
3337 
3338         m_bUserPackagesLoaded = true;
3339     }
3340 
3341     if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
3342     {
3343         m_eState = SHARED_EXTENSIONS;       // Later: SHARED_MODULE
3344     }
3345     else
3346     {
3347         if( m_pScriptSubPackageIterator == nullptr )
3348         {
3349             const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
3350             Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage ];
3351             SAL_WARN_IF(
3352                 !xPackage.is(), "basic",
3353                 ("ScriptExtensionIterator::implGetNextUserScriptPackage():"
3354                  " Invalid package"));
3355             m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
3356         }
3357 
3358         xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
3359         if( !xScriptPackage.is() )
3360         {
3361             delete m_pScriptSubPackageIterator;
3362             m_pScriptSubPackageIterator = nullptr;
3363             m_iUserPackage++;
3364         }
3365     }
3366 
3367     return xScriptPackage;
3368 }
3369 
3370 Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextSharedScriptPackage( bool& rbPureDialogLib )
3371 {
3372     Reference< deployment::XPackage > xScriptPackage;
3373 
3374     if( !m_bSharedPackagesLoaded )
3375     {
3376         try
3377         {
3378             Reference< XExtensionManager > xSharedManager = ExtensionManager::get( m_xContext );
3379             m_aSharedPackagesSeq = xSharedManager->getDeployedExtensions("shared",
3380                                                                          Reference< task::XAbortChannel >(),
3381                                                                          Reference< ucb::XCommandEnvironment >() );
3382         }
3383         catch(const css::uno::DeploymentException& )
3384         {
3385             // Special Office installations may not contain deployment code
3386             return xScriptPackage;
3387         }
3388 
3389         m_bSharedPackagesLoaded = true;
3390     }
3391 
3392     if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
3393     {
3394         m_eState = BUNDLED_EXTENSIONS;
3395     }
3396     else
3397     {
3398         if( m_pScriptSubPackageIterator == nullptr )
3399         {
3400             const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
3401             Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage ];
3402             SAL_WARN_IF(
3403                 !xPackage.is(), "basic",
3404                 ("ScriptExtensionIterator::implGetNextSharedScriptPackage():"
3405                  " Invalid package"));
3406             m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
3407         }
3408 
3409         xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
3410         if( !xScriptPackage.is() )
3411         {
3412             delete m_pScriptSubPackageIterator;
3413             m_pScriptSubPackageIterator = nullptr;
3414             m_iSharedPackage++;
3415         }
3416     }
3417 
3418     return xScriptPackage;
3419 }
3420 
3421 Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextBundledScriptPackage( bool& rbPureDialogLib )
3422 {
3423     Reference< deployment::XPackage > xScriptPackage;
3424 
3425     if( !m_bBundledPackagesLoaded )
3426     {
3427         try
3428         {
3429             Reference< XExtensionManager > xManager = ExtensionManager::get( m_xContext );
3430             m_aBundledPackagesSeq = xManager->getDeployedExtensions("bundled",
3431                                                                     Reference< task::XAbortChannel >(),
3432                                                                     Reference< ucb::XCommandEnvironment >() );
3433         }
3434         catch(const css::uno::DeploymentException& )
3435         {
3436             // Special Office installations may not contain deployment code
3437             return xScriptPackage;
3438         }
3439 
3440         m_bBundledPackagesLoaded = true;
3441     }
3442 
3443     if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
3444     {
3445         m_eState = END_REACHED;
3446     }
3447     else
3448     {
3449         if( m_pScriptSubPackageIterator == nullptr )
3450         {
3451             const Reference< deployment::XPackage >* pBundledPackages = m_aBundledPackagesSeq.getConstArray();
3452             Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage ];
3453             SAL_WARN_IF(
3454                 !xPackage.is(), "basic",
3455                 ("ScriptExtensionIterator::implGetNextBundledScriptPackage():"
3456                  " Invalid package"));
3457             m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
3458         }
3459 
3460         xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
3461         if( !xScriptPackage.is() )
3462         {
3463             delete m_pScriptSubPackageIterator;
3464             m_pScriptSubPackageIterator = nullptr;
3465             m_iBundledPackage++;
3466         }
3467     }
3468 
3469     return xScriptPackage;
3470 }
3471 
3472 }   // namespace basic
3473 
3474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3475