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