/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XContainer.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <vcl/svapp.hxx>
#include <vos/mutex.hxx>
#include <tools/errinf.hxx>
#include <osl/mutex.hxx>
#include <vos/diagnose.hxx>
#include <rtl/uri.hxx>
#include <rtl/strbuf.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/anytostring.hxx>

#include "namecont.hxx"
#include <basic/basicmanagerrepository.hxx>
#include <tools/diagnose_ex.h>
#include <tools/urlobj.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/pathoptions.hxx>
#include <svtools/sfxecode.hxx>
#include <svtools/ehdl.hxx>
#include <basic/basmgr.hxx>
#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
#include <com/sun/star/xml/sax/XParser.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/uno/DeploymentException.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/script/LibraryNotLoadedException.hpp>
#include <com/sun/star/script/vba/VBAScriptEventId.hpp>
#include <com/sun/star/deployment/ExtensionManager.hpp>
#include <comphelper/storagehelper.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <basic/sbmod.hxx>

namespace basic
{

using namespace com::sun::star::document;
using namespace com::sun::star::container;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::io;
using namespace com::sun::star::ucb;
using namespace com::sun::star::script;
using namespace com::sun::star::beans;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star::util;
using namespace com::sun::star::task;
using namespace com::sun::star::embed;
using namespace com::sun::star::frame;
using namespace com::sun::star::deployment;
using namespace com::sun::star;
using namespace cppu;
using namespace rtl;
using namespace osl;

using com::sun::star::uno::Reference;

// #i34411: Flag for error handling during migration
static bool GbMigrationSuppressErrors = false;

//============================================================================
// Implementation class NameContainer

// Methods XElementAccess
Type NameContainer::getElementType()
	throw(RuntimeException)
{
	return mType;
}

sal_Bool NameContainer::hasElements()
	throw(RuntimeException)
{
	sal_Bool bRet = (mnElementCount > 0);
	return bRet;
}

// Methods XNameAccess
Any NameContainer::getByName( const OUString& aName )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    NameContainerNameMap::iterator aIt = mHashMap.find( aName );
	if( aIt == mHashMap.end() )
	{
		throw NoSuchElementException();
	}
	sal_Int32 iHashResult = (*aIt).second;
	Any aRetAny = mValues.getConstArray()[ iHashResult ];
	return aRetAny;
}

Sequence< OUString > NameContainer::getElementNames()
	throw(RuntimeException)
{
	return mNames;
}

sal_Bool NameContainer::hasByName( const OUString& aName )
	throw(RuntimeException)
{
	NameContainerNameMap::iterator aIt = mHashMap.find( aName );
	sal_Bool bRet = ( aIt != mHashMap.end() );
	return bRet;
}


// Methods XNameReplace
void NameContainer::replaceByName( const OUString& aName, const Any& aElement )
	throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
{
	Type aAnyType = aElement.getValueType();
    if( mType != aAnyType )
		throw IllegalArgumentException();

	NameContainerNameMap::iterator aIt = mHashMap.find( aName );
	if( aIt == mHashMap.end() )
	{
		throw NoSuchElementException();
	}
	sal_Int32 iHashResult = (*aIt).second;
	Any aOldElement = mValues.getConstArray()[ iHashResult ];
	mValues.getArray()[ iHashResult ] = aElement;


	// Fire event
	if( maContainerListeners.getLength() > 0 )
	{
    	ContainerEvent aEvent;
    	aEvent.Source = mpxEventSource;
    	aEvent.Accessor <<= aName;
    	aEvent.Element = aElement;
    	aEvent.ReplacedElement = aOldElement;
        maContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvent );
    }

    /*  After the container event has been fired (one listener will update the
        core Basic manager), fire change event. Listeners can rely that the
        Basic source code of the core Basic manager is up-to-date. */
    if( maChangesListeners.getLength() > 0 )
    {
        ChangesEvent aEvent;
        aEvent.Source = mpxEventSource;
        aEvent.Base <<= aEvent.Source;
        aEvent.Changes.realloc( 1 );
        aEvent.Changes[ 0 ].Accessor <<= aName;
        aEvent.Changes[ 0 ].Element <<= aElement;
    	aEvent.Changes[ 0 ].ReplacedElement = aOldElement;
        maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
    }
}


// Methods XNameContainer
void NameContainer::insertByName( const OUString& aName, const Any& aElement )
	throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
{
	Type aAnyType = aElement.getValueType();
    if( mType != aAnyType )
		throw IllegalArgumentException();

	NameContainerNameMap::iterator aIt = mHashMap.find( aName );
	if( aIt != mHashMap.end() )
	{
		throw ElementExistException();
	}

	sal_Int32 nCount = mNames.getLength();
	mNames.realloc( nCount + 1 );
	mValues.realloc( nCount + 1 );
	mNames.getArray()[ nCount ] = aName;
	mValues.getArray()[ nCount ] = aElement;

	mHashMap[ aName ] = nCount;
	mnElementCount++;

	// Fire event
	if( maContainerListeners.getLength() > 0 )
	{
    	ContainerEvent aEvent;
    	aEvent.Source = mpxEventSource;
    	aEvent.Accessor <<= aName;
    	aEvent.Element = aElement;
        maContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
	}

    /*  After the container event has been fired (one listener will update the
        core Basic manager), fire change event. Listeners can rely that the
        Basic source code of the core Basic manager is up-to-date. */
    if( maChangesListeners.getLength() > 0 )
    {
        ChangesEvent aEvent;
        aEvent.Source = mpxEventSource;
        aEvent.Base <<= aEvent.Source;
        aEvent.Changes.realloc( 1 );
        aEvent.Changes[ 0 ].Accessor <<= aName;
        aEvent.Changes[ 0 ].Element <<= aElement;
        maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
    }
}

void NameContainer::removeByName( const OUString& aName )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
	NameContainerNameMap::iterator aIt = mHashMap.find( aName );
	if( aIt == mHashMap.end() )
	{
		throw NoSuchElementException();
	}

	sal_Int32 iHashResult = (*aIt).second;
	Any aOldElement = mValues.getConstArray()[ iHashResult ];
	mHashMap.erase( aIt );
	sal_Int32 iLast = mNames.getLength() - 1;
	if( iLast != iHashResult )
	{
		OUString* pNames = mNames.getArray();
		Any* pValues = mValues.getArray();
		pNames[ iHashResult ] = pNames[ iLast ];
		pValues[ iHashResult ] = pValues[ iLast ];
		mHashMap[ pNames[ iHashResult ] ] = iHashResult;
	}
	mNames.realloc( iLast );
	mValues.realloc( iLast );
	mnElementCount--;

	// Fire event
	if( maContainerListeners.getLength() > 0 )
	{
    	ContainerEvent aEvent;
    	aEvent.Source = mpxEventSource;
    	aEvent.Accessor <<= aName;
    	aEvent.Element = aOldElement;
        maContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
	}

    /*  After the container event has been fired (one listener will update the
        core Basic manager), fire change event. Listeners can rely that the
        Basic source code of the core Basic manager is up-to-date. */
    if( maChangesListeners.getLength() > 0 )
    {
        ChangesEvent aEvent;
        aEvent.Source = mpxEventSource;
        aEvent.Base <<= aEvent.Source;
        aEvent.Changes.realloc( 1 );
        aEvent.Changes[ 0 ].Accessor <<= aName;
        // aEvent.Changes[ 0 ].Element remains empty (meaning "replaced with nothing")
        aEvent.Changes[ 0 ].ReplacedElement = aOldElement;
        maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
    }
}


// Methods XContainer
void SAL_CALL NameContainer::addContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
	if( !xListener.is() )
		throw RuntimeException();
	Reference< XInterface > xIface( xListener, UNO_QUERY );
	maContainerListeners.addInterface( xIface );
}

void SAL_CALL NameContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
	if( !xListener.is() )
		throw RuntimeException();
	Reference< XInterface > xIface( xListener, UNO_QUERY );
	maContainerListeners.removeInterface( xIface );
}

// Methods XChangesNotifier
void SAL_CALL NameContainer::addChangesListener( const Reference< XChangesListener >& xListener )
    throw (RuntimeException)
{
	if( !xListener.is() )
		throw RuntimeException();
	Reference< XInterface > xIface( xListener, UNO_QUERY );
	maChangesListeners.addInterface( xIface );
}

void SAL_CALL NameContainer::removeChangesListener( const Reference< XChangesListener >& xListener )
    throw (RuntimeException)
{
	if( !xListener.is() )
		throw RuntimeException();
	Reference< XInterface > xIface( xListener, UNO_QUERY );
	maChangesListeners.removeInterface( xIface );
}

//============================================================================
// ModifiableHelper

void ModifiableHelper::setModified( sal_Bool _bModified )
{
    if ( _bModified == mbModified )
        return;
    mbModified = _bModified;

    if ( m_aModifyListeners.getLength() == 0 )
        return;

    EventObject aModifyEvent( m_rEventSource );
    m_aModifyListeners.notifyEach( &XModifyListener::modified, aModifyEvent );
}

//============================================================================

VBAScriptListenerContainer::VBAScriptListenerContainer( ::osl::Mutex& rMutex ) :
    VBAScriptListenerContainer_BASE( rMutex )
{
}

bool VBAScriptListenerContainer::implTypedNotify( const Reference< vba::XVBAScriptListener >& rxListener, const vba::VBAScriptEvent& rEvent ) throw (Exception)
{
    rxListener->notifyVBAScriptEvent( rEvent );
    return true;    // notify all other listeners too
}

//============================================================================

// Implementation class SfxLibraryContainer
DBG_NAME( SfxLibraryContainer )

// Ctor
SfxLibraryContainer::SfxLibraryContainer( void )
	: SfxLibraryContainer_BASE( maMutex )

    , maVBAScriptListeners( maMutex )
    , mnRunningVBAScripts( 0 )
    , mbVBACompat( sal_False )
    , maModifiable( *this, maMutex )
    , maNameContainer( getCppuType( (Reference< XNameAccess >*) NULL ) )
    , mbOldInfoFormat( sal_False )
    , mbOasis2OOoFormat( sal_False )
    , mpBasMgr( NULL )
    , mbOwnBasMgr( sal_False )
{
    DBG_CTOR( SfxLibraryContainer, NULL );

	mxMSF = comphelper::getProcessServiceFactory();
	if( !mxMSF.is() )
	{
		OSL_ENSURE( 0, "### couln't get ProcessServiceFactory\n" );
	}

	mxSFI = Reference< XSimpleFileAccess >( mxMSF->createInstance
		( OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
	if( !mxSFI.is() )
	{
		OSL_ENSURE( 0, "### couln't create SimpleFileAccess component\n" );
	}

	mxStringSubstitution = Reference< XStringSubstitution >( mxMSF->createInstance
		( OUString::createFromAscii( "com.sun.star.util.PathSubstitution" ) ), UNO_QUERY );
	if( !mxStringSubstitution.is() )
	{
		OSL_ENSURE( 0, "### couln't create PathSubstitution component\n" );
	}
}

SfxLibraryContainer::~SfxLibraryContainer()
{
    if( mbOwnBasMgr )
        BasicManager::LegacyDeleteBasicManager( mpBasMgr );
    DBG_DTOR( SfxLibraryContainer, NULL );
}

void SfxLibraryContainer::checkDisposed() const
{
    if ( isDisposed() )
        throw DisposedException( ::rtl::OUString(), *const_cast< SfxLibraryContainer* >( this ) );
}

void SfxLibraryContainer::enterMethod()
{
    maMutex.acquire();
    checkDisposed();
}

void SfxLibraryContainer::leaveMethod()
{
    maMutex.release();
}

BasicManager* SfxLibraryContainer::getBasicManager( void )
{
    if ( mpBasMgr )
        return mpBasMgr;

    Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
    OSL_ENSURE( xDocument.is(), "SfxLibraryContainer::getBasicManager: cannot obtain a BasicManager without document!" );
    if ( xDocument.is() )
        mpBasMgr = BasicManagerRepository::getDocumentBasicManager( xDocument );

    return mpBasMgr;
}

// Methods XStorageBasedLibraryContainer
Reference< XStorage > SAL_CALL SfxLibraryContainer::getRootStorage() throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    return mxStorage;
}

void SAL_CALL SfxLibraryContainer::setRootStorage( const Reference< XStorage >& _rxRootStorage ) throw (IllegalArgumentException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    if ( !_rxRootStorage.is() )
        throw IllegalArgumentException();

	mxStorage = _rxRootStorage;
	onNewRootStorage();
}

void SAL_CALL SfxLibraryContainer::storeLibrariesToStorage( const Reference< XStorage >& _rxRootStorage ) throw (IllegalArgumentException, WrappedTargetException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    if ( !_rxRootStorage.is() )
        throw IllegalArgumentException();

    try
    {
        storeLibraries_Impl( _rxRootStorage, sal_True );
    }
    catch( const Exception& )
    {
        throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
    }
}


// Methods XModifiable
sal_Bool SfxLibraryContainer::isModified() throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	if ( maModifiable.isModified() )
		return sal_True;

	// the library container is not modified, go through the libraries and check whether they are modified
	Sequence< OUString > aNames = maNameContainer.getElementNames();
	const OUString* pNames = aNames.getConstArray();
	sal_Int32 nNameCount = aNames.getLength();

	for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
	{
		OUString aName = pNames[ i ];
        SfxLibrary* pImplLib = getImplLib( aName );
		if( pImplLib->isModified() )
		{
			if ( aName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Standard") ) ) )
			{
				// this is a workaround that has to be implemented because
				// empty standard library should stay marked as modified
				// but should not be treated as modified while it is empty
				if ( pImplLib->hasElements() )
					return sal_True;
			}
			else
				return sal_True;
		}
	}

	return sal_False;
}

void SAL_CALL SfxLibraryContainer::setModified( sal_Bool _bModified ) throw (PropertyVetoException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    maModifiable.setModified( _bModified );
}

void SAL_CALL SfxLibraryContainer::addModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    maModifiable.addModifyListener( _rxListener );
}

void SAL_CALL SfxLibraryContainer::removeModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    maModifiable.removeModifyListener( _rxListener );
}

// Methods XPersistentLibraryContainer
Any SAL_CALL SfxLibraryContainer::getRootLocation() throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    return makeAny( getRootStorage() );
}

::rtl::OUString SAL_CALL SfxLibraryContainer::getContainerLocationName() throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    return maLibrariesDir;
}

void SAL_CALL SfxLibraryContainer::storeLibraries(  ) throw (WrappedTargetException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    try
    {
	    storeLibraries_Impl( mxStorage, mxStorage.is()  );
        // we need to store *all* libraries if and only if we are based on a storage:
        // in this case, storeLibraries_Impl will remove the source storage, after loading
        // all libraries, so we need to force them to be stored, again
    }
    catch( const Exception& )
    {
        throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
    }
}

static void checkAndCopyFileImpl( const INetURLObject& rSourceFolderInetObj,
								  const INetURLObject& rTargetFolderInetObj,
								  const OUString& rCheckFileName,
								  const OUString& rCheckExtension,
								  Reference< XSimpleFileAccess > xSFI )
{
	INetURLObject aTargetFolderInetObj( rTargetFolderInetObj );
	aTargetFolderInetObj.insertName( rCheckFileName, sal_True, INetURLObject::LAST_SEGMENT,
									 sal_True, INetURLObject::ENCODE_ALL );
	aTargetFolderInetObj.setExtension( rCheckExtension );
	OUString aTargetFile = aTargetFolderInetObj.GetMainURL( INetURLObject::NO_DECODE );
	if( !xSFI->exists( aTargetFile ) )
	{
		INetURLObject aSourceFolderInetObj( rSourceFolderInetObj );
		aSourceFolderInetObj.insertName( rCheckFileName, sal_True, INetURLObject::LAST_SEGMENT,
										 sal_True, INetURLObject::ENCODE_ALL );
		aSourceFolderInetObj.setExtension( rCheckExtension );
		OUString aSourceFile = aSourceFolderInetObj.GetMainURL( INetURLObject::NO_DECODE );
		xSFI->copy( aSourceFile, aTargetFile );
	}
}

static void createVariableURL( OUString& rStr, const OUString& rLibName,
							   const OUString& rInfoFileName, bool bUser )
{
	if( bUser )
		rStr = OUString::createFromAscii( "$(USER)/basic/" );
	else
		rStr = OUString::createFromAscii( "$(INST)/share/basic/" );

	rStr += rLibName;
	rStr += OUString::createFromAscii( "/" );
	rStr += rInfoFileName;
	rStr += OUString::createFromAscii( ".xlb/" );
}

sal_Bool SfxLibraryContainer::init( const OUString& rInitialDocumentURL, const uno::Reference< embed::XStorage >& rxInitialStorage )
{
    // this might be called from within the ctor, and the impl_init might (indirectly) create
    // an UNO reference to ourself.
    // Ensure that we're not destroyed while we're in here
    osl_incrementInterlockedCount( &m_refCount );
    sal_Bool bSuccess = init_Impl( rInitialDocumentURL, rxInitialStorage );
    osl_decrementInterlockedCount( &m_refCount );

    return bSuccess;
}

sal_Bool SfxLibraryContainer::init_Impl(
    const OUString& rInitialDocumentURL, const uno::Reference< embed::XStorage >& rxInitialStorage )
{
	uno::Reference< embed::XStorage > xStorage = rxInitialStorage;

    maInitialDocumentURL = rInitialDocumentURL;
    maInfoFileName = OUString::createFromAscii( getInfoFileName() );
	maOldInfoFileName = OUString::createFromAscii( getOldInfoFileName() );
	maLibElementFileExtension = OUString::createFromAscii( getLibElementFileExtension() );
	maLibrariesDir = OUString::createFromAscii( getLibrariesDir() );

    meInitMode = DEFAULT;
    INetURLObject aInitUrlInetObj( maInitialDocumentURL );
    OUString aInitFileName = aInitUrlInetObj.GetMainURL( INetURLObject::NO_DECODE );
    if( aInitFileName.getLength() )
    {
        // We need a BasicManager to avoid problems
        StarBASIC* pBas = new StarBASIC();
        mpBasMgr = new BasicManager( pBas );
        mbOwnBasMgr = sal_True;

        OUString aExtension = aInitUrlInetObj.getExtension();
        if( aExtension.compareToAscii( "xlc" ) == COMPARE_EQUAL )
        {
            meInitMode = CONTAINER_INIT_FILE;
	        INetURLObject aLibPathInetObj( aInitUrlInetObj );
			aLibPathInetObj.removeSegment();
	        maLibraryPath = aLibPathInetObj.GetMainURL( INetURLObject::NO_DECODE );
        }
        else if( aExtension.compareToAscii( "xlb" ) == COMPARE_EQUAL )
        {
            meInitMode = LIBRARY_INIT_FILE;
        	uno::Reference< embed::XStorage > xDummyStor;
            ::xmlscript::LibDescriptor aLibDesc;
            sal_Bool bReadIndexFile = implLoadLibraryIndexFile( NULL, aLibDesc, xDummyStor, aInitFileName );
           	return bReadIndexFile;
        }
        else
        {
            // Decide between old and new document
            sal_Bool bOldStorage = SotStorage::IsOLEStorage( aInitFileName );
            if ( bOldStorage )
            {
                meInitMode = OLD_BASIC_STORAGE;
                importFromOldStorage( aInitFileName );
                return sal_True;
            }
            else
            {
                meInitMode = OFFICE_DOCUMENT;
                try
                {
                    xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( aInitFileName, embed::ElementModes::READ );
                }
                catch ( uno::Exception& )
                {
                    // TODO: error handling
                }
            }
        }
    }
    else
    {
        // Default pathes
        maLibraryPath = SvtPathOptions().GetBasicPath();
    }

	Reference< XParser > xParser( mxMSF->createInstance(
		OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Parser") ) ), UNO_QUERY );
	if( !xParser.is() )
	{
		OSL_ENSURE( 0, "### couln't create sax parser component\n" );
		return sal_False;
	}

	uno::Reference< io::XInputStream > xInput;

	mxStorage = xStorage;
	sal_Bool bStorage = mxStorage.is();


	// #110009: Scope to force the StorageRefs to be destructed and
	// so the streams to be closed before the preload operation
	{
	// #110009

	uno::Reference< embed::XStorage > xLibrariesStor;
	String aFileName;

	int nPassCount = 1;
	if( !bStorage && meInitMode == DEFAULT )
		nPassCount = 2;
	for( int nPass = 0 ; nPass < nPassCount ; nPass++ )
	{
		if( bStorage )
		{
			OSL_ENSURE( meInitMode == DEFAULT || meInitMode == OFFICE_DOCUMENT,
				"### Wrong InitMode for document\n" );
			try
			{
				uno::Reference< io::XStream > xStream;
				xLibrariesStor = xStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
                //if ( !xLibrariesStor.is() )
                    // TODO: the method must either return a storage or throw an exception
                    //throw uno::RuntimeException();

                if ( xLibrariesStor.is() )
                {
                    aFileName = maInfoFileName;
                    aFileName += String( RTL_CONSTASCII_USTRINGPARAM("-lc.xml") );

                    try
                    {
                        xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
                    }
                    catch( uno::Exception& )
                    {}

                    if( !xStream.is() )
                    {
                        mbOldInfoFormat = true;

                        // Check old version
                        aFileName = maOldInfoFileName;
                        aFileName += String( RTL_CONSTASCII_USTRINGPARAM(".xml") );

                        try
                        {
                            xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
                        }
                        catch( uno::Exception& )
                        {}

                        if( !xStream.is() )
                        {
                            // Check for EA2 document version with wrong extensions
                            aFileName = maOldInfoFileName;
                            aFileName += String( RTL_CONSTASCII_USTRINGPARAM(".xli") );
                            xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
                        }
                    }
				}

				if ( xStream.is() )
					xInput = xStream->getInputStream();
			}
			catch( uno::Exception& )
			{
                // TODO: error handling?
			}
		}
		else
		{
			INetURLObject* pLibInfoInetObj = NULL;
			if( meInitMode == CONTAINER_INIT_FILE )
			{
				aFileName = aInitFileName;
			}
			else
			{
				if( nPass == 1 )
					pLibInfoInetObj = new INetURLObject( String(maLibraryPath).GetToken(0) );
				else
					pLibInfoInetObj = new INetURLObject( String(maLibraryPath).GetToken(1) );
				pLibInfoInetObj->insertName( maInfoFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				pLibInfoInetObj->setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlc") ) );
				aFileName = pLibInfoInetObj->GetMainURL( INetURLObject::NO_DECODE );
			}

			try
			{
				xInput = mxSFI->openFileRead( aFileName );
			}
			catch( Exception& )
			{
				xInput.clear();
                if( nPass == 0 )
                {
		            SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFileName );
                    sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
                    ErrorHandler::HandleError( nErrorCode );
                }
			}

			// Old variant?
			if( !xInput.is() && nPass == 0 )
			{
				INetURLObject aLibInfoInetObj( String(maLibraryPath).GetToken(1) );
				aLibInfoInetObj.insertName( maOldInfoFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				aLibInfoInetObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xli") ) );
				aFileName = aLibInfoInetObj.GetMainURL( INetURLObject::NO_DECODE );

				try
				{
					xInput = mxSFI->openFileRead( aFileName );
					mbOldInfoFormat = true;
				}
				catch( Exception& )
				{
    				xInput.clear();
		            SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFileName );
                    sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
                    ErrorHandler::HandleError( nErrorCode );
				}
			}

			delete pLibInfoInetObj;
		}

		if( xInput.is() )
        {
		    InputSource source;
		    source.aInputStream = xInput;
		    source.sSystemId 	= aFileName;

		    // start parsing
		    ::xmlscript::LibDescriptorArray* pLibArray = new ::xmlscript::LibDescriptorArray();

            try
            {
                xParser->setDocumentHandler( ::xmlscript::importLibraryContainer( pLibArray ) );
                xParser->parseStream( source );
            }
            catch ( xml::sax::SAXException& e )
            {
                (void) e; // avoid warning
                OSL_ENSURE( 0, OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
                return sal_False;
            }
            catch ( io::IOException& e )
            {
                (void) e; // avoid warning
                OSL_ENSURE( 0, OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
                return sal_False;
            }

		    sal_Int32 nLibCount = pLibArray->mnLibCount;
		    for( sal_Int32 i = 0 ; i < nLibCount ; i++ )
		    {
			    ::xmlscript::LibDescriptor& rLib = pLibArray->mpLibs[i];

			    // Check storage URL
			    OUString aStorageURL = rLib.aStorageURL;
			    if( !bStorage && !aStorageURL.getLength() && nPass == 0 )
			    {
					String aLibraryPath;
					if( meInitMode == CONTAINER_INIT_FILE )
						aLibraryPath = maLibraryPath;
					else
						aLibraryPath = String(maLibraryPath).GetToken(1);
					INetURLObject aInetObj( aLibraryPath );

				    aInetObj.insertName( rLib.aName, sal_True, INetURLObject::LAST_SEGMENT,
					    sal_True, INetURLObject::ENCODE_ALL );
				    OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
				    if( mxSFI->isFolder( aLibDirPath ) )
				    {
						createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, true );
                        maModifiable.setModified( sal_True );
				    }
				    else if( rLib.bLink )
				    {
					    // Check "share" path
					    INetURLObject aShareInetObj( String(maLibraryPath).GetToken(0) );
					    aShareInetObj.insertName( rLib.aName, sal_True, INetURLObject::LAST_SEGMENT,
						    sal_True, INetURLObject::ENCODE_ALL );
					    OUString aShareLibDirPath = aShareInetObj.GetMainURL( INetURLObject::NO_DECODE );
					    if( mxSFI->isFolder( aShareLibDirPath ) )
					    {
							createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, false );
                            maModifiable.setModified( sal_True );
					    }
						else
						{
							// #i25537: Ignore lib if library folder does not really exist
							continue;
						}
				    }
			    }

			    OUString aLibName = rLib.aName;

			    // If the same library name is used by the shared and the
			    // user lib container index files the user file wins
			    if( nPass == 1 && hasByName( aLibName ) )
				    continue;

			    SfxLibrary* pImplLib;
			    if( rLib.bLink )
			    {
				    Reference< XNameAccess > xLib =
					    createLibraryLink( aLibName, rLib.aStorageURL, rLib.bReadOnly );
				    pImplLib = static_cast< SfxLibrary* >( xLib.get() );
			    }
			    else
			    {
				    Reference< XNameContainer > xLib = createLibrary( aLibName );
				    pImplLib = static_cast< SfxLibrary* >( xLib.get() );
				    pImplLib->mbLoaded = sal_False;
				    pImplLib->mbReadOnly = rLib.bReadOnly;
				    if( !bStorage )
					    checkStorageURL( rLib.aStorageURL, pImplLib->maLibInfoFileURL,
                            pImplLib->maStorageURL, pImplLib->maUnexpandedStorageURL );
			    }
				maModifiable.setModified( sal_False );

			    // Read library info files
			    if( !mbOldInfoFormat )
			    {
        		    uno::Reference< embed::XStorage > xLibraryStor;
          		    if( !pImplLib->mbInitialised && bStorage )
				    {
						try {
							xLibraryStor = xLibrariesStor->openStorageElement( rLib.aName,
																				embed::ElementModes::READ );
						}
						catch( uno::Exception& )
						{
                        #if OSL_DEBUG_LEVEL > 0
                            Any aError( ::cppu::getCaughtException() );
                            ::rtl::OStringBuffer aMessage;
                            aMessage.append( "couln't open sub storage for library '" );
                            aMessage.append( ::rtl::OUStringToOString( rLib.aName, osl_getThreadTextEncoding() ) );
                            aMessage.append( "'.\n\nException:" );
                            aMessage.append( ::rtl::OUStringToOString( ::comphelper::anyToString( aError ), osl_getThreadTextEncoding() ) );
			                OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
                        #endif
						}
				    }

				    // Link is already initialised in createLibraryLink()
				    if( !pImplLib->mbInitialised && (!bStorage || xLibraryStor.is()) )
				    {
					    OUString aIndexFileName;
					    sal_Bool bLoaded = implLoadLibraryIndexFile( pImplLib, rLib, xLibraryStor, aIndexFileName );
					    if( bLoaded && aLibName != rLib.aName )
					    {
						    OSL_ENSURE( 0, "Different library names in library"
							    " container and library info files!\n" );
					    }
						if( GbMigrationSuppressErrors && !bLoaded )
							removeLibrary( aLibName );
				    }
			    }
			    else if( !bStorage )
			    {
				    // Write new index file immediately because otherwise
				    // the library elements will be lost when storing into
				    // the new info format
				    uno::Reference< embed::XStorage > xTmpStorage;
				    implStoreLibraryIndexFile( pImplLib, rLib, xTmpStorage );
			    }

			    implImportLibDescriptor( pImplLib, rLib );

			    if( nPass == 1 )
			    {
				    pImplLib->mbSharedIndexFile = sal_True;
				    pImplLib->mbReadOnly = sal_True;
			    }
		    }

		    // Keep flag for documents to force writing the new index files
		    if( !bStorage )
			    mbOldInfoFormat = sal_False;

		    delete pLibArray;
        }
		// Only in the first pass it's an error when no index file is found
		else if( nPass == 0 )
		{
			return sal_False;
		}
	}

	// #110009: END Scope to force the StorageRefs to be destructed
	}
	// #110009

	if( !bStorage && meInitMode == DEFAULT )
    {
        try
        {
            implScanExtensions();
        }
        catch( uno::Exception& )
        {
            // TODO: error handling?
            OSL_ASSERT( "Cannot access extensions!" );
        }
    }

	// #110009 Preload?
    {
	    Sequence< OUString > aNames = maNameContainer.getElementNames();
	    const OUString* pNames = aNames.getConstArray();
	    sal_Int32 nNameCount = aNames.getLength();
	    for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
	    {
		    OUString aName = pNames[ i ];
            SfxLibrary* pImplLib = getImplLib( aName );
		    if( pImplLib->mbPreload )
			    loadLibrary( aName );
	    }
    }

	// #118803# upgrade installation 7.0 -> 8.0
	if( meInitMode == DEFAULT )
	{
		INetURLObject aUserBasicInetObj( String(maLibraryPath).GetToken(1) );
		OUString aStandardStr( RTL_CONSTASCII_USTRINGPARAM("Standard") );

		static char strPrevFolderName_1[] = "__basic_80";
		static char strPrevFolderName_2[] = "__basic_80_2";
		INetURLObject aPrevUserBasicInetObj_1( aUserBasicInetObj );
		aPrevUserBasicInetObj_1.removeSegment();
		INetURLObject aPrevUserBasicInetObj_2 = aPrevUserBasicInetObj_1;
		aPrevUserBasicInetObj_1.Append( strPrevFolderName_1 );
		aPrevUserBasicInetObj_2.Append( strPrevFolderName_2 );

		// #i93163
		bool bCleanUp = false;
		try
		{
			INetURLObject aPrevUserBasicInetObj = aPrevUserBasicInetObj_1;
			String aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::NO_DECODE );
			bool bSecondTime = false;
			if( mxSFI->isFolder( aPrevFolder ) )
			{
				// #110101 Check if Standard folder exists and is complete
				INetURLObject aUserBasicStandardInetObj( aUserBasicInetObj );
				aUserBasicStandardInetObj.insertName( aStandardStr, sal_True, INetURLObject::LAST_SEGMENT,
													  sal_True, INetURLObject::ENCODE_ALL );
				INetURLObject aPrevUserBasicStandardInetObj( aPrevUserBasicInetObj );
				aPrevUserBasicStandardInetObj.insertName( aStandardStr, sal_True, INetURLObject::LAST_SEGMENT,
														sal_True, INetURLObject::ENCODE_ALL );
				OUString aPrevStandardFolder = aPrevUserBasicStandardInetObj.GetMainURL( INetURLObject::NO_DECODE );
				if( mxSFI->isFolder( aPrevStandardFolder ) )
				{
					OUString aXlbExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlb") ) );
					OUString aCheckFileName;

					// Check if script.xlb exists
					aCheckFileName = OUString( RTL_CONSTASCII_USTRINGPARAM("script") );
					checkAndCopyFileImpl( aUserBasicStandardInetObj,
										  aPrevUserBasicStandardInetObj,
										  aCheckFileName, aXlbExtension, mxSFI );

					// Check if dialog.xlb exists
					aCheckFileName = OUString( RTL_CONSTASCII_USTRINGPARAM("dialog") );
					checkAndCopyFileImpl( aUserBasicStandardInetObj,
										  aPrevUserBasicStandardInetObj,
										  aCheckFileName, aXlbExtension, mxSFI );

					// Check if module1.xba exists
					OUString aXbaExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xba") ) );
					aCheckFileName = OUString( RTL_CONSTASCII_USTRINGPARAM("Module1") );
					checkAndCopyFileImpl( aUserBasicStandardInetObj,
										  aPrevUserBasicStandardInetObj,
										  aCheckFileName, aXbaExtension, mxSFI );
				}
				else
				{
					String aStandardFolder = aUserBasicStandardInetObj.GetMainURL( INetURLObject::NO_DECODE );
					mxSFI->copy( aStandardFolder, aPrevStandardFolder );
				}

				String aPrevCopyToFolder = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::NO_DECODE );
				mxSFI->copy( aPrevFolder, aPrevCopyToFolder );
			}
			else
			{
				bSecondTime = true;
				aPrevUserBasicInetObj = aPrevUserBasicInetObj_2;
				aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::NO_DECODE );
			}
			if( mxSFI->isFolder( aPrevFolder ) )
			{
				SfxLibraryContainer* pPrevCont = createInstanceImpl();
				Reference< XInterface > xRef = static_cast< XInterface* >( static_cast< OWeakObject* >(pPrevCont) );

				// Rename previous basic folder to make storage URLs correct during initialisation
				String aFolderUserBasic = aUserBasicInetObj.GetMainURL( INetURLObject::NO_DECODE );
				INetURLObject aUserBasicTmpInetObj( aUserBasicInetObj );
				aUserBasicTmpInetObj.removeSegment();
				aUserBasicTmpInetObj.Append( "__basic_tmp" );
				String aFolderTmp = aUserBasicTmpInetObj.GetMainURL( INetURLObject::NO_DECODE );

				mxSFI->move( aFolderUserBasic, aFolderTmp );
				try
				{
					mxSFI->move( aPrevFolder, aFolderUserBasic );
				}
				catch( Exception& )
				{
					// Move back user/basic folder
					try
					{
           				mxSFI->kill( aFolderUserBasic );
					}
					catch( Exception& )
					{}
					mxSFI->move( aFolderTmp, aFolderUserBasic );
					throw;
				}

				INetURLObject aPrevUserBasicLibInfoInetObj( aUserBasicInetObj );
				aPrevUserBasicLibInfoInetObj.insertName( maInfoFileName, sal_True, INetURLObject::LAST_SEGMENT,
													sal_True, INetURLObject::ENCODE_ALL );
				aPrevUserBasicLibInfoInetObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlc") ) );
				OUString aLibInfoFileName = aPrevUserBasicLibInfoInetObj.GetMainURL( INetURLObject::NO_DECODE );
				Sequence<Any> aInitSeq( 1 );
				aInitSeq.getArray()[0] <<= aLibInfoFileName;
				GbMigrationSuppressErrors = true;
				pPrevCont->initialize( aInitSeq );
				GbMigrationSuppressErrors = false;

				// Rename folders back
				mxSFI->move( aFolderUserBasic, aPrevFolder );
				mxSFI->move( aFolderTmp, aFolderUserBasic );

				OUString aUserSearchStr   = OUString::createFromAscii( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE" );
				OUString aSharedSearchStr = OUString::createFromAscii( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" );
            	OUString aBundledSearchStr = OUString::createFromAscii( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" );
				OUString aInstSearchStr   = OUString::createFromAscii( "$(INST)" );

				Sequence< OUString > aNames = pPrevCont->getElementNames();
				const OUString* pNames = aNames.getConstArray();
				sal_Int32 nNameCount = aNames.getLength();

				for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
				{
					OUString aLibName = pNames[ i ];
					if( hasByName( aLibName ) )
					{
						if( aLibName == aStandardStr )
						{
							SfxLibrary* pImplLib = getImplLib( aStandardStr );
							INetURLObject aStandardFolderInetObj( pImplLib->maStorageURL );
							String aStandardFolder = pImplLib->maStorageURL;
            				mxSFI->kill( aStandardFolder );
						}
						else
						{
							continue;
						}
					}

					SfxLibrary* pImplLib = pPrevCont->getImplLib( aLibName );
					if( pImplLib->mbLink )
					{
						OUString aStorageURL = pImplLib->maUnexpandedStorageURL;
						bool bCreateLink = true;
						if( aStorageURL.indexOf( aUserSearchStr   ) != -1 ||
							aStorageURL.indexOf( aSharedSearchStr ) != -1 ||
							aStorageURL.indexOf( aBundledSearchStr ) != -1 ||
							aStorageURL.indexOf( aInstSearchStr   ) != -1 )
						{
							bCreateLink = false;
						}
						if( bCreateLink )
							createLibraryLink( aLibName, pImplLib->maStorageURL, pImplLib->mbReadOnly );
					}
					else
					{
						// Move folder if not already done
						INetURLObject aUserBasicLibFolderInetObj( aUserBasicInetObj );
    					aUserBasicLibFolderInetObj.Append( aLibName );
						String aLibFolder = aUserBasicLibFolderInetObj.GetMainURL( INetURLObject::NO_DECODE );

						INetURLObject aPrevUserBasicLibFolderInetObj( aPrevUserBasicInetObj );
    					aPrevUserBasicLibFolderInetObj.Append( aLibName );
						String aPrevLibFolder = aPrevUserBasicLibFolderInetObj.GetMainURL( INetURLObject::NO_DECODE );

						if( mxSFI->isFolder( aPrevLibFolder ) && !mxSFI->isFolder( aLibFolder ) )
							mxSFI->move( aPrevLibFolder, aLibFolder );

						if( aLibName == aStandardStr )
                   			maNameContainer.removeByName( aLibName );

						// Create library
						Reference< XNameContainer > xLib = createLibrary( aLibName );
           				SfxLibrary* pNewLib = static_cast< SfxLibrary* >( xLib.get() );
						pNewLib->mbLoaded = false;
						pNewLib->implSetModified( sal_False );
						checkStorageURL( aLibFolder, pNewLib->maLibInfoFileURL,
							pNewLib->maStorageURL, pNewLib->maUnexpandedStorageURL );

						uno::Reference< embed::XStorage > xDummyStor;
						::xmlscript::LibDescriptor aLibDesc;
						/*sal_Bool bReadIndexFile =*/ implLoadLibraryIndexFile
							( pNewLib, aLibDesc, xDummyStor, pNewLib->maLibInfoFileURL );
						implImportLibDescriptor( pNewLib, aLibDesc );
					}
				}
				mxSFI->kill( aPrevFolder );
			}
		}
		catch( Exception& )
		{
			bCleanUp = true;
		}

		// #i93163
		if( bCleanUp )
		{
			DBG_ERROR( "Upgrade of Basic installation failed somehow" );

			static char strErrorSavFolderName[] = "__basic_80_err";
			INetURLObject aPrevUserBasicInetObj_Err( aUserBasicInetObj );
			aPrevUserBasicInetObj_Err.removeSegment();
			aPrevUserBasicInetObj_Err.Append( strErrorSavFolderName );
			String aPrevFolder_Err = aPrevUserBasicInetObj_Err.GetMainURL( INetURLObject::NO_DECODE );

			bool bSaved = false;
			try
			{
				String aPrevFolder_1 = aPrevUserBasicInetObj_1.GetMainURL( INetURLObject::NO_DECODE );
				if( mxSFI->isFolder( aPrevFolder_1 ) )
				{
					mxSFI->move( aPrevFolder_1, aPrevFolder_Err );
					bSaved = true;
				}
			}
			catch( Exception& )
			{}
			try
			{
				String aPrevFolder_2 = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::NO_DECODE );
				if( !bSaved && mxSFI->isFolder( aPrevFolder_2 ) )
					mxSFI->move( aPrevFolder_2, aPrevFolder_Err );
				else
					mxSFI->kill( aPrevFolder_2 );
			}
			catch( Exception& )
			{}
		}
	}

	return sal_True;
}

void SfxLibraryContainer::implScanExtensions( void )
{
	ScriptExtensionIterator aScriptIt;
	rtl::OUString aLibURL;

	bool bPureDialogLib = false;
	while( (aLibURL = aScriptIt.nextBasicOrDialogLibrary( bPureDialogLib )).getLength() > 0 )
	{
		if( bPureDialogLib && maInfoFileName.equalsAscii( "script" ) )
			continue;

		// Extract lib name
		sal_Int32 nLen = aLibURL.getLength();
		sal_Int32 indexLastSlash = aLibURL.lastIndexOf( '/' );
		sal_Int32 nReduceCopy = 0;
		if( indexLastSlash == nLen - 1 )
		{
			nReduceCopy = 1;
			indexLastSlash = aLibURL.lastIndexOf( '/', nLen - 1 );
		}

		OUString aLibName = aLibURL.copy( indexLastSlash + 1, nLen - indexLastSlash - nReduceCopy - 1 );

	    // If a library of the same exists the existing library wins
	    if( hasByName( aLibName ) )
		    continue;

		// Add index file to URL
		OUString aIndexFileURL = aLibURL;
		if( nReduceCopy == 0 )
			aIndexFileURL += OUString::createFromAscii( "/" );
		aIndexFileURL += maInfoFileName;
		aIndexFileURL += OUString::createFromAscii( ".xlb" );

		// Create link
		const bool bReadOnly = false;
	    Reference< XNameAccess > xLib =
		    createLibraryLink( aLibName, aIndexFileURL, bReadOnly );
    }
}

// Handle maLibInfoFileURL and maStorageURL correctly
void SfxLibraryContainer::checkStorageURL( const OUString& aSourceURL,
    OUString& aLibInfoFileURL, OUString& aStorageURL, OUString& aUnexpandedStorageURL )
{
    OUString aExpandedSourceURL = expand_url( aSourceURL );
    if( aExpandedSourceURL != aSourceURL )
        aUnexpandedStorageURL = aSourceURL;

	INetURLObject aInetObj( aExpandedSourceURL );
    OUString aExtension = aInetObj.getExtension();
    if( aExtension.compareToAscii( "xlb" ) == COMPARE_EQUAL )
    {
        // URL to xlb file
		aLibInfoFileURL = aExpandedSourceURL;
        aInetObj.removeSegment();
		aStorageURL = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
    }
    else
    {
        // URL to library folder
        aStorageURL = aExpandedSourceURL;
		aInetObj.insertName( maInfoFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
		aInetObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlb") ) );
		aLibInfoFileURL = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
    }
}

SfxLibrary* SfxLibraryContainer::getImplLib( const String& rLibraryName )
{
	Any aLibAny = maNameContainer.getByName( rLibraryName ) ;
	Reference< XNameAccess > xNameAccess;
	aLibAny >>= xNameAccess;
	SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
    return pImplLib;
}


// Storing with password encryption

// Empty implementation, avoids unneccesary implementation in dlgcont.cxx
sal_Bool SfxLibraryContainer::implStorePasswordLibrary(
    SfxLibrary*,
    const OUString&,
    const uno::Reference< embed::XStorage >&, const uno::Reference< task::XInteractionHandler >&  )
{
    return sal_False;
}

sal_Bool SfxLibraryContainer::implStorePasswordLibrary(
    SfxLibrary* /*pLib*/,
    const ::rtl::OUString& /*aName*/,
    const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& /*xStorage*/,
    const ::rtl::OUString& /*aTargetURL*/,
    const Reference< XSimpleFileAccess > /*xToUseSFI*/,
    const uno::Reference< task::XInteractionHandler >&  )
{
    return sal_False;
}

sal_Bool SfxLibraryContainer::implLoadPasswordLibrary(
    SfxLibrary* /*pLib*/,
    const OUString& /*Name*/,
    sal_Bool /*bVerifyPasswordOnly*/ )
throw(WrappedTargetException, RuntimeException)
{
    return sal_True;
}



#define EXPAND_PROTOCOL "vnd.sun.star.expand"
#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

OUString SfxLibraryContainer::createAppLibraryFolder
    ( SfxLibrary* pLib, const OUString& aName )
{
	OUString aLibDirPath = pLib->maStorageURL;
	if( !aLibDirPath.getLength() )
    {
		INetURLObject aInetObj( String(maLibraryPath).GetToken(1) );
		aInetObj.insertName( aName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
        checkStorageURL( aInetObj.GetMainURL( INetURLObject::NO_DECODE ), pLib->maLibInfoFileURL,
            pLib->maStorageURL, pLib->maUnexpandedStorageURL );
		aLibDirPath = pLib->maStorageURL;
    }

	if( !mxSFI->isFolder( aLibDirPath ) )
    {
	    try
	    {
		    mxSFI->createFolder( aLibDirPath );
        }
        catch( Exception& )
        {}
    }

    return aLibDirPath;
}

// Storing
void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
	const OUString& aName, const uno::Reference< embed::XStorage >& xStorage )
{
	OUString aDummyLocation;
	Reference< XSimpleFileAccess > xDummySFA;
	Reference< XInteractionHandler > xDummyHandler;
	implStoreLibrary( pLib, aName, xStorage, aDummyLocation, xDummySFA, xDummyHandler );
}

// New variant for library export
void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
	const OUString& aName, const uno::Reference< embed::XStorage >& xStorage,
	const ::rtl::OUString& aTargetURL, Reference< XSimpleFileAccess > xToUseSFI,
	const Reference< XInteractionHandler >& xHandler )
{
	sal_Bool bLink = pLib->mbLink;
	sal_Bool bStorage = xStorage.is() && !bLink;

	Sequence< OUString > aElementNames = pLib->getElementNames();
	sal_Int32 nNameCount = aElementNames.getLength();
	const OUString* pNames = aElementNames.getConstArray();

	if( bStorage )
	{
		for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
		{
			OUString aElementName = pNames[ i ];

			OUString aStreamName = aElementName;
			aStreamName += String( RTL_CONSTASCII_USTRINGPARAM(".xml") );

			/*Any aElement = pLib->getByName( aElementName );*/
			if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
            {
            #if OSL_DEBUG_LEVEL > 0
                ::rtl::OStringBuffer aMessage;
                aMessage.append( "invalid library element '" );
                aMessage.append( ::rtl::OUStringToOString( aElementName, osl_getThreadTextEncoding() ) );
                aMessage.append( "'." );
			    OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
            #endif
                continue;
            }
			try {
				uno::Reference< io::XStream > xElementStream = xStorage->openStreamElement(
																	aStreamName,
																	embed::ElementModes::READWRITE );
                //if ( !xElementStream.is() )
                //    throw uno::RuntimeException(); // TODO: method must either return the stream or throw an exception

				String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
				OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );

				uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
				OSL_ENSURE( xProps.is(), "The StorageStream must implement XPropertySet interface!\n" );
                //if ( !xProps.is() ) //TODO
                //    throw uno::RuntimeException();

                if ( xProps.is() )
                {
                    xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );

                    // #87671 Allow encryption
//REMOVE	                        aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("Encrypted") );
                    aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "UseCommonStoragePasswordEncryption" ) );
                    xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) );

                    Reference< XOutputStream > xOutput = xElementStream->getOutputStream();
					Reference< XNameContainer > xLib( pLib );
                    writeLibraryElement( xLib, aElementName, xOutput );
					// writeLibraryElement closes the stream
                    // xOutput->closeOutput();
                }
			}
			catch( uno::Exception& )
			{
				OSL_ENSURE( sal_False, "Problem during storing of library!\n" );
                // TODO: error handling?
			}
		}

		pLib->storeResourcesToStorage( xStorage );
	}
	else
	{
		// Export?
		bool bExport = aTargetURL.getLength();
		try
		{
			Reference< XSimpleFileAccess > xSFI = mxSFI;
			if( xToUseSFI.is() )
				xSFI = xToUseSFI;

            OUString aLibDirPath;
			if( bExport )
			{
				INetURLObject aInetObj( aTargetURL );
				aInetObj.insertName( aName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );

				if( !xSFI->isFolder( aLibDirPath ) )
					xSFI->createFolder( aLibDirPath );

				pLib->storeResourcesToURL( aLibDirPath, xHandler );
			}
			else
			{
	            aLibDirPath = createAppLibraryFolder( pLib, aName );
				pLib->storeResources();
			}

			for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
			{
				OUString aElementName = pNames[ i ];

				INetURLObject aElementInetObj( aLibDirPath );
				aElementInetObj.insertName( aElementName, sal_False,
					INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				aElementInetObj.setExtension( maLibElementFileExtension );
				String aElementPath( aElementInetObj.GetMainURL( INetURLObject::NO_DECODE ) );

				/*Any aElement = pLib->getByName( aElementName );*/
				if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
                {
                #if OSL_DEBUG_LEVEL > 0
                    ::rtl::OStringBuffer aMessage;
                    aMessage.append( "invalid library element '" );
                    aMessage.append( ::rtl::OUStringToOString( aElementName, osl_getThreadTextEncoding() ) );
                    aMessage.append( "'." );
			        OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
                #endif
                    continue;
                }

				// TODO: Check modified
	            try
	            {
				    if( xSFI->exists( aElementPath ) )
					    xSFI->kill( aElementPath );
					Reference< XOutputStream > xOutput = xSFI->openFileWrite( aElementPath );
					Reference< XNameContainer > xLib( pLib );
				    writeLibraryElement( xLib, aElementName, xOutput );
				    xOutput->closeOutput();
                }
        		catch( Exception& )
                {
					if( bExport )
						throw;

		            SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aElementPath );
                    sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
            	    ErrorHandler::HandleError( nErrorCode );
                }
			}
		}
		catch( Exception& )
		{
			if( bExport )
				throw;
		}
	}
}

void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
	const ::xmlscript::LibDescriptor& rLib, const uno::Reference< embed::XStorage >& xStorage )
{
	OUString aDummyLocation;
	Reference< XSimpleFileAccess > xDummySFA;
	implStoreLibraryIndexFile( pLib, rLib, xStorage, aDummyLocation, xDummySFA );
}

// New variant for library export
void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
	const ::xmlscript::LibDescriptor& rLib, const uno::Reference< embed::XStorage >& xStorage,
	const ::rtl::OUString& aTargetURL, Reference< XSimpleFileAccess > xToUseSFI )
{
	// Create sax writer
	Reference< XExtendedDocumentHandler > xHandler(
		mxMSF->createInstance(
			OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer") ) ), UNO_QUERY );
	if( !xHandler.is() )
	{
		OSL_ENSURE( 0, "### couln't create sax-writer component\n" );
		return;
	}

	sal_Bool bLink = pLib->mbLink;
	sal_Bool bStorage = xStorage.is() && !bLink;

	// Write info file
	uno::Reference< io::XOutputStream > xOut;
	uno::Reference< io::XStream > xInfoStream;
	if( bStorage )
	{
		OUString aStreamName( maInfoFileName );
		aStreamName += String( RTL_CONSTASCII_USTRINGPARAM("-lb.xml") );

		try {
			xInfoStream = xStorage->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
            OSL_ENSURE( xInfoStream.is(), "No stream!\n" );
			uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY );
            //if ( !xProps.is() )
            //    throw uno::RuntimeException(); // TODO

            if ( xProps.is() )
            {
                String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
                OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
                xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );

                // #87671 Allow encryption
//REMOVE	                aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("Encrypted") );
                aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "UseCommonStoragePasswordEncryption" ) );
                xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) );

                xOut = xInfoStream->getOutputStream();
            }
		}
		catch( uno::Exception& )
		{
			OSL_ENSURE( sal_False, "Problem during storing of library index file!\n" );
            // TODO: error handling?
		}
	}
	else
	{
		// Export?
		bool bExport = aTargetURL.getLength();
		Reference< XSimpleFileAccess > xSFI = mxSFI;
		if( xToUseSFI.is() )
			xSFI = xToUseSFI;

        OUString aLibInfoPath;
		if( bExport )
		{
			INetURLObject aInetObj( aTargetURL );
			aInetObj.insertName( rLib.aName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
			OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
			if( !xSFI->isFolder( aLibDirPath ) )
				xSFI->createFolder( aLibDirPath );

			aInetObj.insertName( maInfoFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
			aInetObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlb") ) );
			aLibInfoPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );
		}
		else
		{
			createAppLibraryFolder( pLib, rLib.aName );
			aLibInfoPath = pLib->maLibInfoFileURL;
		}

		try
		{
		    if( xSFI->exists( aLibInfoPath ) )
			    xSFI->kill( aLibInfoPath );
		    xOut = xSFI->openFileWrite( aLibInfoPath );
        }
        catch( Exception& )
        {
			if( bExport )
				throw;

			SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
            sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
            ErrorHandler::HandleError( nErrorCode );
        }
	}
	if( !xOut.is() )
	{
		OSL_ENSURE( 0, "### couln't open output stream\n" );
		return;
	}

	Reference< XActiveDataSource > xSource( xHandler, UNO_QUERY );
	xSource->setOutputStream( xOut );

    xmlscript::exportLibrary( xHandler, rLib );
}


sal_Bool SfxLibraryContainer::implLoadLibraryIndexFile(  SfxLibrary* pLib,
    ::xmlscript::LibDescriptor& rLib, const uno::Reference< embed::XStorage >& xStorage, const OUString& aIndexFileName )
{
	Reference< XParser > xParser( mxMSF->createInstance(
		OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Parser") ) ), UNO_QUERY );
	if( !xParser.is() )
	{
		OSL_ENSURE( 0, "### couln't create sax parser component\n" );
		return sal_False;
	}

	sal_Bool bLink = sal_False;
	sal_Bool bStorage = sal_False;
    if( pLib )
    {
	    bLink = pLib->mbLink;
	    bStorage = xStorage.is() && !bLink;
    }

	// Read info file
	uno::Reference< io::XInputStream > xInput;
    String aLibInfoPath;
	if( bStorage )
	{
		aLibInfoPath = maInfoFileName;
		aLibInfoPath += String( RTL_CONSTASCII_USTRINGPARAM("-lb.xml") );

		try {
			uno::Reference< io::XStream > xInfoStream =
						xStorage->openStreamElement( aLibInfoPath, embed::ElementModes::READ );
			xInput = xInfoStream->getInputStream();
		}
		catch( uno::Exception& )
		{}
	}
	else
	{
		// Create Input stream
        //String aLibInfoPath; // attention: THIS PROBLEM MUST BE REVIEWED BY SCRIPTING OWNER!!!

        if( pLib )
        {
            createAppLibraryFolder( pLib, rLib.aName );
            aLibInfoPath = pLib->maLibInfoFileURL;
        }
        else
            aLibInfoPath = aIndexFileName;

		try
		{
			xInput = mxSFI->openFileRead( aLibInfoPath );
		}
		catch( Exception& )
		{
            xInput.clear();
			if( !GbMigrationSuppressErrors )
			{
				SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
				sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
				ErrorHandler::HandleError( nErrorCode );
			}
		}
	}
	if( !xInput.is() )
	{
		// OSL_ENSURE( 0, "### couln't open input stream\n" );
		return sal_False;
	}

	InputSource source;
	source.aInputStream = xInput;
	source.sSystemId 	= aLibInfoPath;

	// start parsing
	try {
		xParser->setDocumentHandler( ::xmlscript::importLibrary( rLib ) );
		xParser->parseStream( source );
	}
	catch( Exception& )
	{
		// throw WrappedTargetException( OUString::createFromAscii( "parsing error!\n" ),
		//								Reference< XInterface >(),
		//								makeAny( e ) );
		OSL_ENSURE( 0, "Parsing error\n" );
		SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
        sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
        ErrorHandler::HandleError( nErrorCode );
		return sal_False;
	}

    if( !pLib )
    {
		Reference< XNameContainer > xLib = createLibrary( rLib.aName );
		pLib = static_cast< SfxLibrary* >( xLib.get() );
		pLib->mbLoaded = sal_False;
        rLib.aStorageURL = aIndexFileName;
        checkStorageURL( rLib.aStorageURL, pLib->maLibInfoFileURL, pLib->maStorageURL,
            pLib->maUnexpandedStorageURL );

        implImportLibDescriptor( pLib, rLib );
    }

    return sal_True;
}

void SfxLibraryContainer::implImportLibDescriptor
    ( SfxLibrary* pLib, ::xmlscript::LibDescriptor& rLib )
{
    if( !pLib->mbInitialised )
    {
	    sal_Int32 nElementCount = rLib.aElementNames.getLength();
	    const OUString* pElementNames = rLib.aElementNames.getConstArray();
	    Any aDummyElement = createEmptyLibraryElement();
	    for( sal_Int32 i = 0 ; i < nElementCount ; i++ )
	    {
		    pLib->maNameContainer.insertByName( pElementNames[i], aDummyElement );
	    }
        pLib->mbPasswordProtected = rLib.bPasswordProtected;
        pLib->mbReadOnly = rLib.bReadOnly;
		pLib->mbPreload  = rLib.bPreload;
        pLib->implSetModified( sal_False );

        pLib->mbInitialised = sal_True;
    }
}


// Methods of new XLibraryStorage interface?
void SfxLibraryContainer::storeLibraries_Impl( const uno::Reference< embed::XStorage >& i_rStorage, sal_Bool bComplete )
{
	const Sequence< OUString > aNames = maNameContainer.getElementNames();
	sal_Int32 nNameCount = aNames.getLength();
    const OUString* pName = aNames.getConstArray();
	const OUString* pNamesEnd = aNames.getConstArray() + nNameCount;

	// Don't count libs from shared index file
	sal_Int32 nLibsToSave = nNameCount;
	for( ; pName != pNamesEnd; ++pName )
	{
        SfxLibrary* pImplLib = getImplLib( *pName );
		if( pImplLib->mbSharedIndexFile || pImplLib->mbExtension )
			nLibsToSave--;
	}
    if( !nLibsToSave )
        return;

	::xmlscript::LibDescriptorArray* pLibArray = new ::xmlscript::LibDescriptorArray( nLibsToSave );

	// Write to storage?
	sal_Bool bStorage = i_rStorage.is();
	uno::Reference< embed::XStorage > xSourceLibrariesStor;
	uno::Reference< embed::XStorage > xTargetLibrariesStor;
    ::rtl::OUString sTempTargetStorName;
    const bool bInplaceStorage = bStorage && ( i_rStorage == mxStorage );
	if ( bStorage )
	{
        // Don't write if only empty standard lib exists
        if ( ( nNameCount == 1 ) && ( aNames[0].equalsAscii( "Standard" ) ) )
        {
		    Any aLibAny = maNameContainer.getByName( aNames[0] );
		    Reference< XNameAccess > xNameAccess;
		    aLibAny >>= xNameAccess;
            if ( !xNameAccess->hasElements() )
                return;
        }

        // create the empty target storage
        try
        {
            ::rtl::OUString sTargetLibrariesStoreName;
            if ( bInplaceStorage )
            {
                // create a temporary target storage
                const ::rtl::OUStringBuffer aTempTargetNameBase = maLibrariesDir + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_temp_" ) );
                sal_Int32 index = 0;
                do
                {
                    ::rtl::OUStringBuffer aTempTargetName( aTempTargetNameBase );
                    aTempTargetName.append( index++ );

                    sTargetLibrariesStoreName = aTempTargetName.makeStringAndClear();
                    if ( !i_rStorage->hasByName( sTargetLibrariesStoreName ) )
                        break;
                }
                while ( true );
                sTempTargetStorName = sTargetLibrariesStoreName;
            }
            else
            {
                sTargetLibrariesStoreName = maLibrariesDir;
			    if ( i_rStorage->hasByName( sTargetLibrariesStoreName ) )
				    i_rStorage->removeElement( sTargetLibrariesStoreName );
            }

            xTargetLibrariesStor.set( i_rStorage->openStorageElement( sTargetLibrariesStoreName, embed::ElementModes::READWRITE ), UNO_QUERY_THROW );
	    }
	    catch( const uno::Exception& )
	    {
            DBG_UNHANDLED_EXCEPTION();
		    return;
	    }

        // open the source storage which might be used to copy yet-unmodified libraries
		try
        {
            if ( mxStorage->hasByName( maLibrariesDir ) )
                xSourceLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, bInplaceStorage ? embed::ElementModes::READWRITE : embed::ElementModes::READ );
            else if ( bInplaceStorage )
                xSourceLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READWRITE );
		}
		catch( const uno::Exception& )
		{
            DBG_UNHANDLED_EXCEPTION();
			return;
        }
	}

	int iArray = 0;
	pName = aNames.getConstArray();
	::xmlscript::LibDescriptor aLibDescriptorForExtensionLibs;
    for( ; pName != pNamesEnd; ++pName )
	{
        SfxLibrary* pImplLib = getImplLib( *pName );
		if( pImplLib->mbSharedIndexFile )
			continue;
		const bool bExtensionLib = pImplLib->mbExtension;
		::xmlscript::LibDescriptor& rLib = bExtensionLib ?
			aLibDescriptorForExtensionLibs : pLibArray->mpLibs[iArray];
		if( !bExtensionLib )
			iArray++;
		rLib.aName = *pName;

		rLib.bLink = pImplLib->mbLink;
		if( !bStorage || pImplLib->mbLink )
		{
			rLib.aStorageURL = ( pImplLib->maUnexpandedStorageURL.getLength() ) ?
				pImplLib->maUnexpandedStorageURL : pImplLib->maLibInfoFileURL;
		}
		rLib.bReadOnly = pImplLib->mbReadOnly;
		rLib.bPreload = pImplLib->mbPreload;
		rLib.bPasswordProtected = pImplLib->mbPasswordProtected;
		rLib.aElementNames = pImplLib->getElementNames();

		if( pImplLib->implIsModified() || bComplete )
		{
            // Can we simply copy the storage?
            if( !mbOldInfoFormat && !pImplLib->implIsModified() && !mbOasis2OOoFormat && xSourceLibrariesStor.is() )
            {
				try
                {
                	xSourceLibrariesStor->copyElementTo( rLib.aName, xTargetLibrariesStor, rLib.aName );
				}
                catch( const uno::Exception& )
				{
                    DBG_UNHANDLED_EXCEPTION();
                    // TODO: error handling?
				}
            }
            else
            {
				uno::Reference< embed::XStorage > xLibraryStor;
				if( bStorage )
				{
					try
                    {
						xLibraryStor = xTargetLibrariesStor->openStorageElement(
																		rLib.aName,
																		embed::ElementModes::READWRITE );
					}
					catch( uno::Exception& )
					{
                    #if OSL_DEBUG_LEVEL > 0
                        Any aError( ::cppu::getCaughtException() );
                        ::rtl::OStringBuffer aMessage;
                        aMessage.append( "couln't create sub storage for library '" );
                        aMessage.append( ::rtl::OUStringToOString( rLib.aName, osl_getThreadTextEncoding() ) );
                        aMessage.append( "'.\n\nException:" );
                        aMessage.append( ::rtl::OUStringToOString( ::comphelper::anyToString( aError ), osl_getThreadTextEncoding() ) );
					    OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
                    #endif
						return;
					}
				}

				// Maybe lib is not loaded?!
				if( bComplete )
					loadLibrary( rLib.aName );

    			if( pImplLib->mbPasswordProtected )
				    implStorePasswordLibrary( pImplLib, rLib.aName, xLibraryStor, uno::Reference< task::XInteractionHandler >() );
                    // TODO: Check return value
                else
				    implStoreLibrary( pImplLib, rLib.aName, xLibraryStor );

                implStoreLibraryIndexFile( pImplLib, rLib, xLibraryStor );
				if( bStorage )
				{
					try
                    {
						uno::Reference< embed::XTransactedObject > xTransact( xLibraryStor, uno::UNO_QUERY_THROW );
						xTransact->commit();
					}
					catch( uno::Exception& )
					{
                        DBG_UNHANDLED_EXCEPTION();
                        // TODO: error handling
					}
				}
            }

			maModifiable.setModified( sal_True );
			pImplLib->implSetModified( sal_False );
		}

        // For container info ReadOnly refers to mbReadOnlyLink
		rLib.bReadOnly = pImplLib->mbReadOnlyLink;
	}

    // if we did an in-place save into a storage (i.e. a save into the storage we were already based on),
    // then we need to clean up the temporary storage we used for this
    if ( bInplaceStorage && sTempTargetStorName.getLength() )
    {
        OSL_ENSURE( xSourceLibrariesStor.is(), "SfxLibrariesContainer::storeLibraries_impl: unexpected: we should have a source storage here!" );
        try
        {
            // for this, we first remove everything from the source storage, then copy the complete content
            // from the temporary target storage. From then on, what used to be the "source storage" becomes
            // the "targt storage" for all subsequent operations.

            // (We cannot simply remove the storage, denoted by maLibrariesDir, from i_rStorage - there might be
            // open references to it.)

            if ( xSourceLibrariesStor.is() )
            {
                // remove
                const Sequence< ::rtl::OUString > aRemoveNames( xSourceLibrariesStor->getElementNames() );
                for (   const ::rtl::OUString* pRemoveName = aRemoveNames.getConstArray();
                        pRemoveName != aRemoveNames.getConstArray() + aRemoveNames.getLength();
                            ++pRemoveName
                    )
                {
                    xSourceLibrariesStor->removeElement( *pRemoveName );
                }

                // copy
                const Sequence< ::rtl::OUString > aCopyNames( xTargetLibrariesStor->getElementNames() );
                for (   const ::rtl::OUString* pCopyName = aCopyNames.getConstArray();
                        pCopyName != aCopyNames.getConstArray() + aCopyNames.getLength();
                        ++pCopyName
                    )
                {
                	xTargetLibrariesStor->copyElementTo( *pCopyName, xSourceLibrariesStor, *pCopyName );
                }
            }

            // close and remove temp target
            xTargetLibrariesStor->dispose();
            i_rStorage->removeElement( sTempTargetStorName );
            xTargetLibrariesStor.clear();
            sTempTargetStorName = ::rtl::OUString();

            // adjust target
            xTargetLibrariesStor = xSourceLibrariesStor;
            xSourceLibrariesStor.clear();
        }
        catch( const Exception& )
        {
        	DBG_UNHANDLED_EXCEPTION();
        }
    }

	if( !mbOldInfoFormat && !maModifiable.isModified() )
		return;
	maModifiable.setModified( sal_False );
    mbOldInfoFormat = sal_False;

	// Write library container info
	// Create sax writer
	Reference< XExtendedDocumentHandler > xHandler(
		mxMSF->createInstance(
			OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer") ) ), UNO_QUERY );
	if( !xHandler.is() )
	{
		OSL_ENSURE( 0, "### couln't create sax-writer component\n" );
		return;
	}

	// Write info file
	uno::Reference< io::XOutputStream > xOut;
	uno::Reference< io::XStream > xInfoStream;
	if( bStorage )
	{
		OUString aStreamName( maInfoFileName );
		aStreamName += String( RTL_CONSTASCII_USTRINGPARAM("-lc.xml") );

		try {
			xInfoStream = xTargetLibrariesStor->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
			uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY );
			OSL_ENSURE ( xProps.is(), "The stream must implement XPropertySet!\n" );
			if ( !xProps.is() )
				throw uno::RuntimeException();

			String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
			OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
			xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );

            // #87671 Allow encryption
			aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("UseCommonStoragePasswordEncryption") );
			xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) );

			xOut = xInfoStream->getOutputStream();
		}
		catch( uno::Exception& )
		{
			sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
			ErrorHandler::HandleError( nErrorCode );
		}
	}
	else
	{
		// Create Output stream
		INetURLObject aLibInfoInetObj( String(maLibraryPath).GetToken(1) );
		aLibInfoInetObj.insertName( maInfoFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
		aLibInfoInetObj.setExtension( OUString( RTL_CONSTASCII_USTRINGPARAM("xlc") ) );
		String aLibInfoPath( aLibInfoInetObj.GetMainURL( INetURLObject::NO_DECODE ) );

		try
		{
		    if( mxSFI->exists( aLibInfoPath ) )
			    mxSFI->kill( aLibInfoPath );
		    xOut = mxSFI->openFileWrite( aLibInfoPath );
        }
        catch( Exception& )
        {
            xOut.clear();
			SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
            sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
            ErrorHandler::HandleError( nErrorCode );
        }

	}
	if( !xOut.is() )
	{
		OSL_ENSURE( 0, "### couln't open output stream\n" );
		return;
	}

	Reference< XActiveDataSource > xSource( xHandler, UNO_QUERY );
	xSource->setOutputStream( xOut );

    try
	{
		xmlscript::exportLibraryContainer( xHandler, pLibArray );
		if ( bStorage )
		{
            uno::Reference< embed::XTransactedObject > xTransact( xTargetLibrariesStor, uno::UNO_QUERY );
            OSL_ENSURE( xTransact.is(), "The storage must implement XTransactedObject!\n" );
            if ( !xTransact.is() )
                throw uno::RuntimeException();

            xTransact->commit();
        }
    }
    catch( uno::Exception& )
    {
		OSL_ENSURE( sal_False, "Problem during storing of libraries!\n" );
        sal_uIntPtr nErrorCode = ERRCODE_IO_GENERAL;
        ErrorHandler::HandleError( nErrorCode );
    }

	delete pLibArray;
}


// Methods XElementAccess
Type SAL_CALL SfxLibraryContainer::getElementType()
	throw(RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	return maNameContainer.getElementType();
}

sal_Bool SfxLibraryContainer::hasElements()
	throw(RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	sal_Bool bRet = maNameContainer.hasElements();
	return bRet;
}

// Methods XNameAccess
Any SfxLibraryContainer::getByName( const OUString& aName )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	Any aRetAny = maNameContainer.getByName( aName ) ;
	return aRetAny;
}

Sequence< OUString > SfxLibraryContainer::getElementNames()
	throw(RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	return maNameContainer.getElementNames();
}

sal_Bool SfxLibraryContainer::hasByName( const OUString& aName )
	throw(RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	return maNameContainer.hasByName( aName ) ;
}

// Methods XLibraryContainer
Reference< XNameContainer > SAL_CALL SfxLibraryContainer::createLibrary( const OUString& Name )
		throw(IllegalArgumentException, ElementExistException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	SfxLibrary* pNewLib = implCreateLibrary( Name );
    pNewLib->maLibElementFileExtension = maLibElementFileExtension;

	createVariableURL( pNewLib->maUnexpandedStorageURL, Name, maInfoFileName, true );

	Reference< XNameAccess > xNameAccess = static_cast< XNameAccess* >( pNewLib );
	Any aElement;
	aElement <<= xNameAccess;
	maNameContainer.insertByName( Name, aElement );
	maModifiable.setModified( sal_True );
    Reference< XNameContainer > xRet( xNameAccess, UNO_QUERY );
	return xRet;
}

Reference< XNameAccess > SAL_CALL SfxLibraryContainer::createLibraryLink
	( const OUString& Name, const OUString& StorageURL, sal_Bool ReadOnly )
		throw(IllegalArgumentException, ElementExistException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    // TODO: Check other reasons to force ReadOnly status
	//if( !ReadOnly )
	//{
	//}

    OUString aLibInfoFileURL;
    OUString aLibDirURL;
    OUString aUnexpandedStorageURL;
    checkStorageURL( StorageURL, aLibInfoFileURL, aLibDirURL, aUnexpandedStorageURL );


	SfxLibrary* pNewLib = implCreateLibraryLink( Name, aLibInfoFileURL, aLibDirURL, ReadOnly );
    pNewLib->maLibElementFileExtension = maLibElementFileExtension;
    pNewLib->maUnexpandedStorageURL = aUnexpandedStorageURL;
    pNewLib->maOrignialStorageURL = StorageURL;

    OUString aInitFileName;
	uno::Reference< embed::XStorage > xDummyStor;
    ::xmlscript::LibDescriptor aLibDesc;
    /*sal_Bool bReadIndexFile = */implLoadLibraryIndexFile( pNewLib, aLibDesc, xDummyStor, aInitFileName );
    implImportLibDescriptor( pNewLib, aLibDesc );

	Reference< XNameAccess > xRet = static_cast< XNameAccess* >( pNewLib );
	Any aElement;
	aElement <<= xRet;
	maNameContainer.insertByName( Name, aElement );
	maModifiable.setModified( sal_True );

	OUString aUserSearchStr   = OUString::createFromAscii( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE" );
	OUString aSharedSearchStr = OUString::createFromAscii( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" );
	OUString aBundledSearchStr = OUString::createFromAscii( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" );
	if( StorageURL.indexOf( aUserSearchStr ) != -1 )
	{
	    pNewLib->mbExtension = sal_True;
	}
	else if( StorageURL.indexOf( aSharedSearchStr ) != -1 || StorageURL.indexOf( aBundledSearchStr ) != -1 )
	{
	    pNewLib->mbExtension = sal_True;
	    pNewLib->mbReadOnly = sal_True;
	}

	return xRet;
}

void SAL_CALL SfxLibraryContainer::removeLibrary( const OUString& Name )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    // Get and hold library before removing
	Any aLibAny = maNameContainer.getByName( Name ) ;
	Reference< XNameAccess > xNameAccess;
	aLibAny >>= xNameAccess;
	SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
	if( pImplLib->mbReadOnly && !pImplLib->mbLink )
		throw IllegalArgumentException();

    // Remove from container
	maNameContainer.removeByName( Name );
	maModifiable.setModified( sal_True );

    // Delete library files, but not for linked libraries
    if( !pImplLib->mbLink )
    {
	    if( mxStorage.is() )
            return;
	    if( xNameAccess->hasElements() )
	    {
		    Sequence< OUString > aNames = pImplLib->getElementNames();
		    sal_Int32 nNameCount = aNames.getLength();
		    const OUString* pNames = aNames.getConstArray();
		    for( sal_Int32 i = 0 ; i < nNameCount ; ++i, ++pNames )
		    {
                pImplLib->removeElementWithoutChecks( *pNames, SfxLibrary::LibraryContainerAccess() );
		    }
	    }

        // Delete index file
        createAppLibraryFolder( pImplLib, Name );
        String aLibInfoPath = pImplLib->maLibInfoFileURL;
		try
		{
		    if( mxSFI->exists( aLibInfoPath ) )
			    mxSFI->kill( aLibInfoPath );
        }
        catch( Exception& ) {}

        // Delete folder if empty
	    INetURLObject aInetObj( String(maLibraryPath).GetToken(1) );
	    aInetObj.insertName( Name, sal_True, INetURLObject::LAST_SEGMENT,
		    sal_True, INetURLObject::ENCODE_ALL );
	    OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::NO_DECODE );

	    try
	    {
	        if( mxSFI->isFolder( aLibDirPath ) )
	        {
                Sequence< OUString > aContentSeq = mxSFI->getFolderContents( aLibDirPath, true );
    		    sal_Int32 nCount = aContentSeq.getLength();
	            if( !nCount )
		            mxSFI->kill( aLibDirPath );
	        }
        }
        catch( Exception& )
        {
        }
    }
}

sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLoaded( const OUString& Name )
	throw(NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
	sal_Bool bRet = pImplLib->mbLoaded;
	return bRet;
}


void SAL_CALL SfxLibraryContainer::loadLibrary( const OUString& Name )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	Any aLibAny = maNameContainer.getByName( Name ) ;
	Reference< XNameAccess > xNameAccess;
	aLibAny >>= xNameAccess;
	SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );

    sal_Bool bLoaded = pImplLib->mbLoaded;
	pImplLib->mbLoaded = sal_True;
	if( !bLoaded && xNameAccess->hasElements() )
	{
        if( pImplLib->mbPasswordProtected )
        {
            implLoadPasswordLibrary( pImplLib, Name );
            return;
        }

		sal_Bool bLink = pImplLib->mbLink;
		sal_Bool bStorage = mxStorage.is() && !bLink;

		uno::Reference< embed::XStorage > xLibrariesStor;
		uno::Reference< embed::XStorage > xLibraryStor;
		if( bStorage )
		{
			try {
				xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
				OSL_ENSURE( xLibrariesStor.is(), "The method must either throw exception or return a storage!\n" );
				if ( !xLibrariesStor.is() )
					throw uno::RuntimeException();

				xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
				OSL_ENSURE( xLibraryStor.is(), "The method must either throw exception or return a storage!\n" );
				if ( !xLibrariesStor.is() )
					throw uno::RuntimeException();
			}
			catch( uno::Exception& )
			{
            #if OSL_DEBUG_LEVEL > 0
                Any aError( ::cppu::getCaughtException() );
                ::rtl::OStringBuffer aMessage;
                aMessage.append( "couln't open sub storage for library '" );
                aMessage.append( ::rtl::OUStringToOString( Name, osl_getThreadTextEncoding() ) );
                aMessage.append( "'.\n\nException:" );
                aMessage.append( ::rtl::OUStringToOString( ::comphelper::anyToString( aError ), osl_getThreadTextEncoding() ) );
			    OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
            #endif
				return;
			}
		}

		Sequence< OUString > aNames = pImplLib->getElementNames();
		sal_Int32 nNameCount = aNames.getLength();
		const OUString* pNames = aNames.getConstArray();
		for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
		{
			OUString aElementName = pNames[ i ];

			OUString aFile;
			uno::Reference< io::XInputStream > xInStream;

			if( bStorage )
			{
				uno::Reference< io::XStream > xElementStream;

				aFile = aElementName;
				aFile += String( RTL_CONSTASCII_USTRINGPARAM(".xml") );

				try {
					xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
				} catch( uno::Exception& )
				{}

				if( !xElementStream.is() )
				{
					// Check for EA2 document version with wrong extensions
					aFile = aElementName;
					aFile += String( RTL_CONSTASCII_USTRINGPARAM(".") );
					aFile += maLibElementFileExtension;
					try {
						xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
					} catch( uno::Exception& )
					{}
				}

				if ( xElementStream.is() )
					xInStream = xElementStream->getInputStream();

				if ( !xInStream.is() )
				{
                #if OSL_DEBUG_LEVEL > 0
                    ::rtl::OStringBuffer aMessage;
                    aMessage.append( "couln't open library element stream - attempted to open library '" );
                    aMessage.append( ::rtl::OUStringToOString( Name, osl_getThreadTextEncoding() ) );
                    aMessage.append( "'." );
					OSL_ENSURE( false, aMessage.makeStringAndClear().getStr() );
                #endif
					return;
				}
			}
			else
			{
		        String aLibDirPath = pImplLib->maStorageURL;
				INetURLObject aElementInetObj( aLibDirPath );
				aElementInetObj.insertName( aElementName, sal_False,
					INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				aElementInetObj.setExtension( maLibElementFileExtension );
				aFile = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );
			}

			Reference< XNameContainer > xLib( pImplLib );
			Any aAny = importLibraryElement( xLib, aElementName, 
					   						 aFile, xInStream );
			if( pImplLib->hasByName( aElementName ) )
            {
                if( aAny.hasValue() )
				    pImplLib->maNameContainer.replaceByName( aElementName, aAny );
            }
			else
            {
				pImplLib->maNameContainer.insertByName( aElementName, aAny );
            }
		}

        pImplLib->implSetModified( sal_False );
	}
}

// Methods XLibraryContainer2
sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLink( const OUString& Name )
    throw (NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
	sal_Bool bRet = pImplLib->mbLink;
	return bRet;
}

OUString SAL_CALL SfxLibraryContainer::getLibraryLinkURL( const OUString& Name )
    throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
	sal_Bool bLink = pImplLib->mbLink;
	if( !bLink )
		throw IllegalArgumentException();
    OUString aRetStr = pImplLib->maLibInfoFileURL;
    return aRetStr;
}

sal_Bool SAL_CALL SfxLibraryContainer::isLibraryReadOnly( const OUString& Name )
    throw (NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
	sal_Bool bRet = pImplLib->mbReadOnly || (pImplLib->mbLink && pImplLib->mbReadOnlyLink);
	return bRet;
}

void SAL_CALL SfxLibraryContainer::setLibraryReadOnly( const OUString& Name, sal_Bool bReadOnly )
    throw (NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
    if( pImplLib->mbLink )
    {
        if( pImplLib->mbReadOnlyLink != bReadOnly )
        {
            pImplLib->mbReadOnlyLink = bReadOnly;
            pImplLib->implSetModified( sal_True );
            maModifiable.setModified( sal_True );
        }
    }
    else
    {
        if( pImplLib->mbReadOnly != bReadOnly )
        {
	        pImplLib->mbReadOnly = bReadOnly;
            pImplLib->implSetModified( sal_True );
        }
    }
}

void SAL_CALL SfxLibraryContainer::renameLibrary( const OUString& Name, const OUString& NewName )
    throw (NoSuchElementException, ElementExistException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	if( maNameContainer.hasByName( NewName ) )
		throw ElementExistException();

    // Get and hold library before removing
	Any aLibAny = maNameContainer.getByName( Name ) ;

	// #i24094 Maybe lib is not loaded!
	Reference< XNameAccess > xNameAccess;
	aLibAny >>= xNameAccess;
	SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
	if( pImplLib->mbPasswordProtected && !pImplLib->mbPasswordVerified )
		return;		// Lib with unverified password cannot be renamed
	loadLibrary( Name );

    // Remove from container
	maNameContainer.removeByName( Name );
	maModifiable.setModified( sal_True );

    // Rename library folder, but not for linked libraries
    bool bMovedSuccessful = true;

    // Rename files
    sal_Bool bStorage = mxStorage.is();
    if( !bStorage && !pImplLib->mbLink )
    {
        bMovedSuccessful = false;

	    OUString aLibDirPath = pImplLib->maStorageURL;

	    INetURLObject aDestInetObj( String(maLibraryPath).GetToken(1) );
	    aDestInetObj.insertName( NewName, sal_True, INetURLObject::LAST_SEGMENT,
		    sal_True, INetURLObject::ENCODE_ALL );
	    OUString aDestDirPath = aDestInetObj.GetMainURL( INetURLObject::NO_DECODE );

        // Store new URL
        OUString aLibInfoFileURL = pImplLib->maLibInfoFileURL;
        checkStorageURL( aDestDirPath, pImplLib->maLibInfoFileURL, pImplLib->maStorageURL,
            pImplLib->maUnexpandedStorageURL );

	    try
	    {
	        if( mxSFI->isFolder( aLibDirPath ) )
	        {
			    if( !mxSFI->isFolder( aDestDirPath ) )
				    mxSFI->createFolder( aDestDirPath );

                // Move index file
		        try
		        {
					if( mxSFI->exists( pImplLib->maLibInfoFileURL ) )
						mxSFI->kill( pImplLib->maLibInfoFileURL );
            	    mxSFI->move( aLibInfoFileURL, pImplLib->maLibInfoFileURL );
                }
            	catch( Exception& )
                {
                }

			    Sequence< OUString > aElementNames = xNameAccess->getElementNames();
			    sal_Int32 nNameCount = aElementNames.getLength();
			    const OUString* pNames = aElementNames.getConstArray();
			    for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
			    {
				    OUString aElementName = pNames[ i ];

				    INetURLObject aElementInetObj( aLibDirPath );
				    aElementInetObj.insertName( aElementName, sal_False,
					    INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				    aElementInetObj.setExtension( maLibElementFileExtension );
				    String aElementPath( aElementInetObj.GetMainURL( INetURLObject::NO_DECODE ) );

				    INetURLObject aElementDestInetObj( aDestDirPath );
				    aElementDestInetObj.insertName( aElementName, sal_False,
					    INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
				    aElementDestInetObj.setExtension( maLibElementFileExtension );
				    String aDestElementPath( aElementDestInetObj.GetMainURL( INetURLObject::NO_DECODE ) );

		            try
		            {
					    if( mxSFI->exists( aDestElementPath ) )
						    mxSFI->kill( aDestElementPath );
            	        mxSFI->move( aElementPath, aDestElementPath );
                    }
            		catch( Exception& )
                    {
                    }
			    }
				pImplLib->storeResourcesAsURL( aDestDirPath, NewName );

                // Delete folder if empty
                Sequence< OUString > aContentSeq = mxSFI->getFolderContents( aLibDirPath, true );
    		    sal_Int32 nCount = aContentSeq.getLength();
	            if( !nCount )
                {
       	            mxSFI->kill( aLibDirPath );
                }

                bMovedSuccessful = true;
				pImplLib->implSetModified( sal_True );
	        }
        }
        catch( Exception& )
        {
            // Restore old library
        	maNameContainer.insertByName( Name, aLibAny ) ;
        }
    }

    if( bStorage && !pImplLib->mbLink )
		pImplLib->implSetModified( sal_True );

    if( bMovedSuccessful )
       	maNameContainer.insertByName( NewName, aLibAny ) ;

}


// Methods XInitialization
void SAL_CALL SfxLibraryContainer::initialize( const Sequence< Any >& _rArguments )
    throw (Exception, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	sal_Int32 nArgCount = _rArguments.getLength();
    if ( nArgCount == 1 )
    {
        OUString sInitialDocumentURL;
        Reference< XStorageBasedDocument > xDocument;
        if ( _rArguments[0] >>= sInitialDocumentURL )
        {
            initializeFromDocumentURL( sInitialDocumentURL );
            return;
        }

        if ( _rArguments[0] >>= xDocument )
        {
            initializeFromDocument( xDocument );
            return;
        }
    }

    throw IllegalArgumentException();
}

void SAL_CALL SfxLibraryContainer::initializeFromDocumentURL( const ::rtl::OUString& _rInitialDocumentURL )
{
    init( _rInitialDocumentURL, NULL );
}

void SAL_CALL SfxLibraryContainer::initializeFromDocument( const Reference< XStorageBasedDocument >& _rxDocument )
{
    // check whether this is a valid OfficeDocument, and obtain the document's root storage
    Reference< XStorage > xDocStorage;
    try
    {
        Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY_THROW );
        if ( xSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.OfficeDocument" ) ) ) )
            xDocStorage.set( _rxDocument->getDocumentStorage(), UNO_QUERY_THROW );

        Reference< XModel > xDocument( _rxDocument, UNO_QUERY_THROW );
        Reference< XComponent > xDocComponent( _rxDocument, UNO_QUERY_THROW );

        mxOwnerDocument = xDocument;
        startComponentListening( xDocComponent );
    }
    catch( const Exception& ) { }

    if ( !xDocStorage.is() )
        throw IllegalArgumentException();

    init( OUString(), xDocStorage );
}

// OEventListenerAdapter
void SfxLibraryContainer::_disposing( const EventObject& _rSource )
{
#if OSL_DEBUG_LEVEL > 0
    Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
    OSL_ENSURE( ( xDocument == _rSource.Source ) && xDocument.is(), "SfxLibraryContainer::_disposing: where does this come from?" );
#else
    (void)_rSource;
#endif
    dispose();
}

// OComponentHelper
void SAL_CALL SfxLibraryContainer::disposing()
{
    Reference< XModel > xModel = mxOwnerDocument;
    EventObject aEvent( xModel.get() );
    maVBAScriptListeners.disposing( aEvent );
    stopAllComponentListening();
    mxOwnerDocument = WeakReference< XModel >();
}

// Methods XLibraryContainerPassword
sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordProtected( const OUString& )
    throw (NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    return sal_False;
}

sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordVerified( const OUString& )
    throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	throw IllegalArgumentException();
}

sal_Bool SAL_CALL SfxLibraryContainer::verifyLibraryPassword
    ( const OUString&, const OUString& )
        throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	throw IllegalArgumentException();
}

void SAL_CALL SfxLibraryContainer::changeLibraryPassword(
    const OUString&, const OUString&, const OUString& )
        throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	throw IllegalArgumentException();
}

// Methods XContainer
void SAL_CALL SfxLibraryContainer::addContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	maNameContainer.setEventSource( static_cast< XInterface* >( (OWeakObject*)this ) );
	maNameContainer.addContainerListener( xListener );
}

void SAL_CALL SfxLibraryContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
	maNameContainer.removeContainerListener( xListener );
}

// Methods XLibraryContainerExport
void SAL_CALL SfxLibraryContainer::exportLibrary( const OUString& Name, const OUString& URL,
	const Reference< XInteractionHandler >& Handler )
		throw ( uno::Exception, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );

	Reference< XSimpleFileAccess > xToUseSFI;
	if( Handler.is() )
	{
		xToUseSFI = Reference< XSimpleFileAccess >( mxMSF->createInstance
			( OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
		if( xToUseSFI.is() )
			xToUseSFI->setInteractionHandler( Handler );
	}

	// Maybe lib is not loaded?!
	loadLibrary( Name );

	uno::Reference< ::com::sun::star::embed::XStorage > xDummyStor;
    if( pImplLib->mbPasswordProtected )
		implStorePasswordLibrary( pImplLib, Name, xDummyStor, URL, xToUseSFI, Handler );
    else
		implStoreLibrary( pImplLib, Name, xDummyStor, URL, xToUseSFI, Handler );

	::xmlscript::LibDescriptor aLibDesc;
	aLibDesc.aName = Name;
	aLibDesc.bLink = false;				// Link status gets lost?
	aLibDesc.bReadOnly = pImplLib->mbReadOnly;
	aLibDesc.bPreload = false;			// Preload status gets lost?
	aLibDesc.bPasswordProtected = pImplLib->mbPasswordProtected;
	aLibDesc.aElementNames = pImplLib->getElementNames();

	implStoreLibraryIndexFile( pImplLib, aLibDesc, xDummyStor, URL, xToUseSFI );
}

OUString SfxLibraryContainer::expand_url( const OUString& url )
	throw(::com::sun::star::uno::RuntimeException)
{
    if (0 == url.compareToAscii( RTL_CONSTASCII_STRINGPARAM(EXPAND_PROTOCOL ":") ))
    {
        if( !mxMacroExpander.is() )
        {
            Reference< XPropertySet > xProps( mxMSF, UNO_QUERY );
            OSL_ASSERT( xProps.is() );
            if( xProps.is() )
            {
                Reference< XComponentContext > xContext;
                xProps->getPropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
                OSL_ASSERT( xContext.is() );
                if( xContext.is() )
                {
                    Reference< util::XMacroExpander > xExpander;
                    xContext->getValueByName(
                        OUSTR("/singletons/com.sun.star.util.theMacroExpander") ) >>= xExpander;
                    if(! xExpander.is())
                    {
						throw uno::DeploymentException(
                            OUSTR("no macro expander singleton available!"), Reference< XInterface >() );
                    }
                    MutexGuard guard( Mutex::getGlobalMutex() );
                    if( !mxMacroExpander.is() )
                    {
                        mxMacroExpander = xExpander;
                    }
                }
            }
        }

        if( !mxMacroExpander.is() )
            return url;

        // cut protocol
        OUString macro( url.copy( sizeof (EXPAND_PROTOCOL ":") -1 ) );
        // decode uric class chars
        macro = Uri::decode( macro, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
        // expand macro string
        OUString ret( mxMacroExpander->expandMacros( macro ) );
        return ret;
    }
	else if( mxStringSubstitution.is() )
	{
		OUString ret( mxStringSubstitution->substituteVariables( url, false ) );
        return ret;
	}
    else
    {
        return url;
    }
}

//XLibraryContainer3
OUString SAL_CALL SfxLibraryContainer::getOriginalLibraryLinkURL( const OUString& Name )
    throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    SfxLibrary* pImplLib = getImplLib( Name );
	sal_Bool bLink = pImplLib->mbLink;
	if( !bLink )
		throw IllegalArgumentException();
    OUString aRetStr = pImplLib->maOrignialStorageURL;
    return aRetStr;
}
    

// XVBACompatibility
::sal_Bool SAL_CALL SfxLibraryContainer::getVBACompatibilityMode() throw (RuntimeException)
{
	return mbVBACompat;
}

void SAL_CALL SfxLibraryContainer::setVBACompatibilityMode( ::sal_Bool _vbacompatmodeon ) throw (RuntimeException)
{
    /*  The member variable mbVBACompat must be set first, the following call
        to getBasicManager() may call getVBACompatibilityMode() which returns
        this value. */
    mbVBACompat = _vbacompatmodeon;
	if( BasicManager* pBasMgr = getBasicManager() )
	{
		// get the standard library
        String aLibName = pBasMgr->GetName();
        if ( aLibName.Len() == 0 )
            aLibName = String( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );

		if( StarBASIC* pBasic = pBasMgr->GetLib( aLibName ) )
			pBasic->SetVBAEnabled( _vbacompatmodeon );

        /*  If in VBA compatibility mode, force creation of the VBA Globals
            object. Each application will create an instance of its own
            implementation and store it in its Basic manager. Implementations
            will do all necessary additional initialization, such as
            registering the global "This***Doc" UNO constant, starting the
            document events processor etc.
         */
        if( mbVBACompat ) try
        {
            Reference< XModel > xModel( mxOwnerDocument );   // weak-ref -> ref
            Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
            xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAGlobals" ) ) );
        }
        catch( Exception& )
        {
        }
	}
}

sal_Int32 SAL_CALL SfxLibraryContainer::getRunningVBAScripts() throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    return mnRunningVBAScripts;
}

void SAL_CALL SfxLibraryContainer::addVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener ) throw (RuntimeException)
{
    maVBAScriptListeners.addTypedListener( rxListener );
}

void SAL_CALL SfxLibraryContainer::removeVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener ) throw (RuntimeException)
{
    maVBAScriptListeners.removeTypedListener( rxListener );
}

void SAL_CALL SfxLibraryContainer::broadcastVBAScriptEvent( sal_Int32 nIdentifier, const ::rtl::OUString& rModuleName ) throw (RuntimeException)
{
    // own lock for accessing the number of running scripts
    enterMethod();
    switch( nIdentifier )
    {
        case vba::VBAScriptEventId::SCRIPT_STARTED:
            ++mnRunningVBAScripts;
        break;
        case vba::VBAScriptEventId::SCRIPT_STOPPED:
            --mnRunningVBAScripts;
        break;
    }
    leaveMethod();

    Reference< XModel > xModel = mxOwnerDocument;  // weak-ref -> ref
    Reference< XInterface > xSender( xModel, UNO_QUERY_THROW );
    vba::VBAScriptEvent aEvent( xSender, nIdentifier, rModuleName );
    maVBAScriptListeners.notify( aEvent );
}

// Methods XServiceInfo
::sal_Bool SAL_CALL SfxLibraryContainer::supportsService( const ::rtl::OUString& _rServiceName )
    throw (RuntimeException)
{
    LibraryContainerMethodGuard aGuard( *this );
    Sequence< OUString > aSupportedServices( getSupportedServiceNames() );
    const OUString* pSupportedServices = aSupportedServices.getConstArray();
    for ( sal_Int32 i=0; i<aSupportedServices.getLength(); ++i, ++pSupportedServices )
        if ( *pSupportedServices == _rServiceName )
            return sal_True;
    return sal_False;
}

//============================================================================

// Implementation class SfxLibrary

// Ctor
SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
    const Reference< XMultiServiceFactory >& xMSF, const Reference< XSimpleFileAccess >& xSFI )
		: OComponentHelper( m_aMutex )
		, mxMSF( xMSF )
		, mxSFI( xSFI )
        , mrModifiable( _rModifiable )
		, maNameContainer( aType )
		, mbLoaded( sal_True )
		, mbIsModified( sal_True )
		, mbInitialised( sal_False )
		, mbLink( sal_False )
		, mbReadOnly( sal_False )
		, mbReadOnlyLink( sal_False )
		, mbPreload( sal_False )
		, mbPasswordProtected( sal_False )
		, mbPasswordVerified( sal_False )
		, mbDoc50Password( sal_False )
		, mbSharedIndexFile( sal_False )
		, mbExtension( sal_False )
{
}

SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
    const Reference< XMultiServiceFactory >& xMSF, const Reference< XSimpleFileAccess >& xSFI,
	const OUString& aLibInfoFileURL, const OUString& aStorageURL, sal_Bool ReadOnly )
		: OComponentHelper( m_aMutex )
		, mxMSF( xMSF )
		, mxSFI( xSFI )
        , mrModifiable( _rModifiable )
		, maNameContainer( aType )
		, mbLoaded( sal_False )
		, mbIsModified( sal_True )
		, mbInitialised( sal_False )
		, maLibInfoFileURL( aLibInfoFileURL )
		, maStorageURL( aStorageURL )
		, mbLink( sal_True )
		, mbReadOnly( sal_False )
		, mbReadOnlyLink( ReadOnly )
		, mbPreload( sal_False )
		, mbPasswordProtected( sal_False )
		, mbPasswordVerified( sal_False )
		, mbDoc50Password( sal_False )
		, mbSharedIndexFile( sal_False )
		, mbExtension( sal_False )
{
}

void SfxLibrary::implSetModified( sal_Bool _bIsModified )
{
    if ( mbIsModified == _bIsModified )
        return;
    mbIsModified = _bIsModified;
    if ( mbIsModified )
        mrModifiable.setModified( sal_True );
}

// Methods XInterface
Any SAL_CALL SfxLibrary::queryInterface( const Type& rType )
	throw( RuntimeException )
{
	Any aRet;

    /*
	if( mbReadOnly )
	{
		aRet = Any( ::cppu::queryInterface( rType,
			static_cast< XContainer * >( this ),
			static_cast< XNameAccess * >( this ) ) );
	}
	else
	{
    */
		aRet = Any( ::cppu::queryInterface( rType,
			static_cast< XContainer * >( this ),
			static_cast< XNameContainer * >( this ),
			static_cast< XNameAccess * >( this ),
			static_cast< XElementAccess * >( this ),
			static_cast< XChangesNotifier * >( this ) ) );
	//}
	if( !aRet.hasValue() )
		aRet = OComponentHelper::queryInterface( rType );
	return aRet;
}

// Methods XElementAccess
Type SfxLibrary::getElementType()
	throw(RuntimeException)
{
	return maNameContainer.getElementType();
}

sal_Bool SfxLibrary::hasElements()
	throw(RuntimeException)
{
	sal_Bool bRet = maNameContainer.hasElements();
	return bRet;
}

// Methods XNameAccess
Any SfxLibrary::getByName( const OUString& aName )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    impl_checkLoaded();

	Any aRetAny = maNameContainer.getByName( aName ) ;
	return aRetAny;
}

Sequence< OUString > SfxLibrary::getElementNames()
	throw(RuntimeException)
{
	return maNameContainer.getElementNames();
}

sal_Bool SfxLibrary::hasByName( const OUString& aName )
	throw(RuntimeException)
{
	sal_Bool bRet = maNameContainer.hasByName( aName );
	return bRet;
}

void SfxLibrary::impl_checkReadOnly()
{
	if( mbReadOnly || (mbLink && mbReadOnlyLink) )
        throw IllegalArgumentException(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Library is readonly." ) ),
            // TODO: resource
            *this, 0
        );
}

void SfxLibrary::impl_checkLoaded()
{
    if ( !mbLoaded )
        throw WrappedTargetException(
            ::rtl::OUString(),
            *this,
            makeAny( LibraryNotLoadedException(
                ::rtl::OUString(),
                *this
            ) )
        );
}

// Methods XNameReplace
void SfxLibrary::replaceByName( const OUString& aName, const Any& aElement )
	throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
{
    impl_checkReadOnly();
    impl_checkLoaded();

    OSL_ENSURE( isLibraryElementValid( aElement ), "SfxLibrary::replaceByName: replacing element is invalid!" );

	maNameContainer.replaceByName( aName, aElement );
	implSetModified( sal_True );
}


// Methods XNameContainer
void SfxLibrary::insertByName( const OUString& aName, const Any& aElement )
	throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
{
    impl_checkReadOnly();
    impl_checkLoaded();

    OSL_ENSURE( isLibraryElementValid( aElement ), "SfxLibrary::insertByName: to-be-inserted element is invalid!" );

	maNameContainer.insertByName( aName, aElement );
	implSetModified( sal_True );
}

void SfxLibrary::impl_removeWithoutChecks( const ::rtl::OUString& _rElementName )
{
	maNameContainer.removeByName( _rElementName );
	implSetModified( sal_True );

    // Remove element file
	if( maStorageURL.getLength() )
	{
		INetURLObject aElementInetObj( maStorageURL );
		aElementInetObj.insertName( _rElementName, sal_False,
			INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL );
		aElementInetObj.setExtension( maLibElementFileExtension );
		OUString aFile = aElementInetObj.GetMainURL( INetURLObject::NO_DECODE );

		try
		{
	        if( mxSFI->exists( aFile ) )
		        mxSFI->kill( aFile );
        }
        catch( Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
	}
}

void SfxLibrary::removeByName( const OUString& Name )
	throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    impl_checkReadOnly();
    impl_checkLoaded();
    impl_removeWithoutChecks( Name );
}

// XTypeProvider
Sequence< Type > SfxLibrary::getTypes()
	throw( RuntimeException )
{
	static OTypeCollection * s_pTypes_NameContainer = 0;
	{
		if( !s_pTypes_NameContainer )
		{
			MutexGuard aGuard( Mutex::getGlobalMutex() );
			if( !s_pTypes_NameContainer )
			{
				static OTypeCollection s_aTypes_NameContainer(
					::getCppuType( (const Reference< XNameContainer > *)0 ),
					::getCppuType( (const Reference< XContainer > *)0 ),
					::getCppuType( (const Reference< XChangesNotifier > *)0 ),
					OComponentHelper::getTypes() );
				s_pTypes_NameContainer = &s_aTypes_NameContainer;
			}
		}
		return s_pTypes_NameContainer->getTypes();
	}
}


Sequence< sal_Int8 > SfxLibrary::getImplementationId()
	throw( RuntimeException )
{
	static OImplementationId * s_pId_NameContainer = 0;
	{
		if( !s_pId_NameContainer )
		{
			MutexGuard aGuard( Mutex::getGlobalMutex() );
			if( !s_pId_NameContainer )
			{
				static OImplementationId s_aId_NameContainer;
				s_pId_NameContainer = &s_aId_NameContainer;
			}
		}
		return s_pId_NameContainer->getImplementationId();
	}
}

// Methods XContainer
void SAL_CALL SfxLibrary::addContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
	maNameContainer.setEventSource( static_cast< XInterface* >( (OWeakObject*)this ) );
	maNameContainer.addContainerListener( xListener );
}

void SAL_CALL SfxLibrary::removeContainerListener( const Reference< XContainerListener >& xListener )
	throw (RuntimeException)
{
	maNameContainer.removeContainerListener( xListener );
}

// Methods XChangesNotifier
void SAL_CALL SfxLibrary::addChangesListener( const Reference< XChangesListener >& xListener )
    throw (RuntimeException)
{
	maNameContainer.setEventSource( static_cast< XInterface* >( (OWeakObject*)this ) );
	maNameContainer.addChangesListener( xListener );
}

void SAL_CALL SfxLibrary::removeChangesListener( const Reference< XChangesListener >& xListener )
    throw (RuntimeException)
{
	maNameContainer.removeChangesListener( xListener );
}

//============================================================================
// Implementation class ScriptExtensionIterator

static rtl::OUString aBasicLibMediaType( rtl::OUString::createFromAscii( "application/vnd.sun.star.basic-library" ) );
static rtl::OUString aDialogLibMediaType( rtl::OUString::createFromAscii( "application/vnd.sun.star.dialog-library" ) );

ScriptExtensionIterator::ScriptExtensionIterator( void )
	: m_eState( USER_EXTENSIONS )
	, m_bUserPackagesLoaded( false )
	, m_bSharedPackagesLoaded( false )
    , m_bBundledPackagesLoaded( false )
	, m_iUserPackage( 0 )
	, m_iSharedPackage( 0 )
   	, m_iBundledPackage( 0 )
	, m_pScriptSubPackageIterator( NULL )
{
	Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory();
	Reference< XPropertySet > xProps( xFactory, UNO_QUERY );
	OSL_ASSERT( xProps.is() );
	if (xProps.is())
	{
		xProps->getPropertyValue(
			::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= m_xContext;
		OSL_ASSERT( m_xContext.is() );
	}
	if( !m_xContext.is() )
	{
		throw RuntimeException(
			::rtl::OUString::createFromAscii( "ScriptExtensionIterator::init(), no XComponentContext" ),
			Reference< XInterface >() );
	}
}

rtl::OUString ScriptExtensionIterator::nextBasicOrDialogLibrary( bool& rbPureDialogLib )
{
	rtl::OUString aRetLib;

	while( !aRetLib.getLength() && m_eState != END_REACHED )
	{
		switch( m_eState )
		{
			case USER_EXTENSIONS:
			{
				Reference< deployment::XPackage > xScriptPackage =
					implGetNextUserScriptPackage( rbPureDialogLib );
				if( !xScriptPackage.is() )
					break;

				aRetLib = xScriptPackage->getURL();
				break;
			}

			case SHARED_EXTENSIONS:
			{
				Reference< deployment::XPackage > xScriptPackage =
					implGetNextSharedScriptPackage( rbPureDialogLib );
				if( !xScriptPackage.is() )
					break;

				aRetLib = xScriptPackage->getURL();
				break;
			}
			case BUNDLED_EXTENSIONS:
			{
				Reference< deployment::XPackage > xScriptPackage = 
					implGetNextBundledScriptPackage( rbPureDialogLib );
				if( !xScriptPackage.is() )
					break;

				aRetLib = xScriptPackage->getURL();
				break;
			}
            case END_REACHED:
				VOS_ENSURE( false, "ScriptExtensionIterator::nextBasicOrDialogLibrary(): Invalid case END_REACHED" );
				break;
		}
	}

	return aRetLib;
}

ScriptSubPackageIterator::ScriptSubPackageIterator( Reference< deployment::XPackage > xMainPackage )
	: m_xMainPackage( xMainPackage )
	, m_bIsValid( false )
	, m_bIsBundle( false )
	, m_nSubPkgCount( 0 )
	, m_iNextSubPkg( 0 )
{
	Reference< deployment::XPackage > xScriptPackage;
	if( !m_xMainPackage.is() )
		return;

	// Check if parent package is registered
    beans::Optional< beans::Ambiguous<sal_Bool> > option( m_xMainPackage->isRegistered
		( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
	bool bRegistered = false;
    if( option.IsPresent )
    {
        beans::Ambiguous<sal_Bool> const & reg = option.Value;
        if( !reg.IsAmbiguous && reg.Value )
			bRegistered = true;
    }
	if( bRegistered )
	{
		m_bIsValid = true;
		if( m_xMainPackage->isBundle() )
		{
			m_bIsBundle = true;
			m_aSubPkgSeq = m_xMainPackage->getBundle
				( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
			m_nSubPkgCount = m_aSubPkgSeq.getLength();
		}
	}
}

Reference< deployment::XPackage > ScriptSubPackageIterator::getNextScriptSubPackage
	( bool& rbPureDialogLib )
{
	rbPureDialogLib = false;

	Reference< deployment::XPackage > xScriptPackage;
	if( !m_bIsValid )
		return xScriptPackage;

	if( m_bIsBundle )
	{
		const Reference< deployment::XPackage >* pSeq = m_aSubPkgSeq.getConstArray();
		sal_Int32 iPkg;
		for( iPkg = m_iNextSubPkg ; iPkg < m_nSubPkgCount ; ++iPkg )
		{
			const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
			xScriptPackage = implDetectScriptPackage( xSubPkg, rbPureDialogLib );
			if( xScriptPackage.is() )
				break;
		}
		m_iNextSubPkg = iPkg + 1;
	}
	else
	{
		xScriptPackage = implDetectScriptPackage( m_xMainPackage, rbPureDialogLib );
		m_bIsValid = false;		// No more script packages
	}

	return xScriptPackage;
}

Reference< deployment::XPackage > ScriptSubPackageIterator::implDetectScriptPackage
	( const Reference< deployment::XPackage > xPackage, bool& rbPureDialogLib )
{
	Reference< deployment::XPackage > xScriptPackage;

	if( xPackage.is() )
	{
		const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
		rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
		if( aMediaType.equals( aBasicLibMediaType ) )
		{
			xScriptPackage = xPackage;
		}
		else if( aMediaType.equals( aDialogLibMediaType ) )
		{
			rbPureDialogLib = true;
			xScriptPackage = xPackage;
		}
	}

	return xScriptPackage;
}

Reference< deployment::XPackage > ScriptExtensionIterator::implGetScriptPackageFromPackage
	( const Reference< deployment::XPackage > xPackage, bool& rbPureDialogLib )
{
	rbPureDialogLib = false;

	Reference< deployment::XPackage > xScriptPackage;
	if( !xPackage.is() )
		return xScriptPackage;

	// Check if parent package is registered
    beans::Optional< beans::Ambiguous<sal_Bool> > option( xPackage->isRegistered
		( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() ) );
	bool bRegistered = false;
    if( option.IsPresent )
    {
        beans::Ambiguous<sal_Bool> const & reg = option.Value;
        if( !reg.IsAmbiguous && reg.Value )
			bRegistered = true;
    }
	if( bRegistered )
	{
		if( xPackage->isBundle() )
		{
			Sequence< Reference< deployment::XPackage > > aPkgSeq = xPackage->getBundle
				( Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>() );
			sal_Int32 nPkgCount = aPkgSeq.getLength();
			const Reference< deployment::XPackage >* pSeq = aPkgSeq.getConstArray();
			for( sal_Int32 iPkg = 0 ; iPkg < nPkgCount ; ++iPkg )
			{
				const Reference< deployment::XPackage > xSubPkg = pSeq[ iPkg ];
				const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xSubPkg->getPackageType();
				rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
				if( aMediaType.equals( aBasicLibMediaType ) )
				{
					xScriptPackage = xSubPkg;
					break;
				}
				else if( aMediaType.equals( aDialogLibMediaType ) )
				{
					rbPureDialogLib = true;
					xScriptPackage = xSubPkg;
					break;
				}
			}
		}
		else
		{
			const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = xPackage->getPackageType();
			rtl::OUString aMediaType = xPackageTypeInfo->getMediaType();
			if( aMediaType.equals( aBasicLibMediaType ) )
			{
				xScriptPackage = xPackage;
			}
			else if( aMediaType.equals( aDialogLibMediaType ) )
			{
				rbPureDialogLib = true;
				xScriptPackage = xPackage;
			}
		}
	}

	return xScriptPackage;
}

Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextUserScriptPackage
	( bool& rbPureDialogLib )
{
	Reference< deployment::XPackage > xScriptPackage;

	if( !m_bUserPackagesLoaded )
	{
		try
		{
			Reference< XExtensionManager > xManager =
				ExtensionManager::get( m_xContext );
			m_aUserPackagesSeq = xManager->getDeployedExtensions
				(rtl::OUString::createFromAscii("user"),
                 Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
		}
		catch( com::sun::star::uno::DeploymentException& )
		{
			// Special Office installations may not contain deployment code
			m_eState = END_REACHED;
			return xScriptPackage;
		}

		m_bUserPackagesLoaded = true;
	}

	if( m_iUserPackage == m_aUserPackagesSeq.getLength() )
	{
		m_eState = SHARED_EXTENSIONS;		// Later: SHARED_MODULE
	}
	else
	{
		if( m_pScriptSubPackageIterator == NULL )
		{
			const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
			Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage ];
			VOS_ENSURE( xPackage.is(), "ScriptExtensionIterator::implGetNextUserScriptPackage(): Invalid package" );
			m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
		}

		if( m_pScriptSubPackageIterator != NULL )
		{
			xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
			if( !xScriptPackage.is() )
			{
				delete m_pScriptSubPackageIterator;
				m_pScriptSubPackageIterator = NULL;
				m_iUserPackage++;
			}
		}
	}

	return xScriptPackage;
}

Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextSharedScriptPackage
	( bool& rbPureDialogLib )
{
	Reference< deployment::XPackage > xScriptPackage;

	if( !m_bSharedPackagesLoaded )
	{
		try
		{
			Reference< XExtensionManager > xSharedManager =
				ExtensionManager::get( m_xContext ); 
			m_aSharedPackagesSeq = xSharedManager->getDeployedExtensions
				(rtl::OUString::createFromAscii("shared"),
                 Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
		}
		catch( com::sun::star::uno::DeploymentException& )
		{
			// Special Office installations may not contain deployment code
			return xScriptPackage;
		}

		m_bSharedPackagesLoaded = true;
	}

	if( m_iSharedPackage == m_aSharedPackagesSeq.getLength() )
	{
		m_eState = BUNDLED_EXTENSIONS;
	}
	else
	{
		if( m_pScriptSubPackageIterator == NULL )
		{
			const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
			Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage ];
			VOS_ENSURE( xPackage.is(), "ScriptExtensionIterator::implGetNextSharedScriptPackage(): Invalid package" );
			m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
		}

		if( m_pScriptSubPackageIterator != NULL )
		{
			xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
			if( !xScriptPackage.is() )
			{
				delete m_pScriptSubPackageIterator;
				m_pScriptSubPackageIterator = NULL;
				m_iSharedPackage++;
			}
		}
	}

	return xScriptPackage;
}

Reference< deployment::XPackage > ScriptExtensionIterator::implGetNextBundledScriptPackage
	( bool& rbPureDialogLib )
{
	Reference< deployment::XPackage > xScriptPackage;

	if( !m_bBundledPackagesLoaded )
	{
		try
		{
			Reference< XExtensionManager > xManager =
				ExtensionManager::get( m_xContext ); 
			m_aBundledPackagesSeq = xManager->getDeployedExtensions
				(rtl::OUString::createFromAscii("bundled"),
                 Reference< task::XAbortChannel >(), Reference< ucb::XCommandEnvironment >() );
		}
		catch( com::sun::star::uno::DeploymentException& )
		{
			// Special Office installations may not contain deployment code
			return xScriptPackage;
		}

		m_bBundledPackagesLoaded = true;
	}

	if( m_iBundledPackage == m_aBundledPackagesSeq.getLength() )
	{
		m_eState = END_REACHED;
	}
	else
	{
		if( m_pScriptSubPackageIterator == NULL )
		{
			const Reference< deployment::XPackage >* pBundledPackages = m_aBundledPackagesSeq.getConstArray();
			Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage ];
			VOS_ENSURE( xPackage.is(), "ScriptExtensionIterator::implGetNextBundledScriptPackage(): Invalid package" );
			m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
		}

		if( m_pScriptSubPackageIterator != NULL )
		{
			xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
			if( !xScriptPackage.is() )
			{
				delete m_pScriptSubPackageIterator;
				m_pScriptSubPackageIterator = NULL;
				m_iBundledPackage++;
			}
		}
	}

	return xScriptPackage;
}

}   // namespace basic
