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