summaryrefslogtreecommitdiffstats
path: root/basic/source/uno
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/uno')
-rw-r--r--basic/source/uno/dlgcont.cxx605
-rw-r--r--basic/source/uno/modsizeexceeded.cxx56
-rw-r--r--basic/source/uno/namecont.cxx3498
-rw-r--r--basic/source/uno/scriptcont.cxx1243
4 files changed, 5402 insertions, 0 deletions
diff --git a/basic/source/uno/dlgcont.cxx b/basic/source/uno/dlgcont.cxx
new file mode 100644
index 000000000..974f461b4
--- /dev/null
+++ b/basic/source/uno/dlgcont.cxx
@@ -0,0 +1,605 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XInputStreamProvider.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/resource/StringResourceWithStorage.hpp>
+#include <com/sun/star/resource/StringResourceWithLocation.hpp>
+#include <com/sun/star/document/GraphicStorageHandler.hpp>
+#include <com/sun/star/document/XGraphicStorageHandler.hpp>
+#include <dlgcont.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <xmlscript/xmldlg_imexp.hxx>
+#include <sot/storage.hxx>
+#include <svtools/sfxecode.hxx>
+#include <svtools/ehdl.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+namespace basic
+{
+
+using namespace com::sun::star::document;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::script;
+using namespace com::sun::star::xml::sax;
+using namespace com::sun::star;
+using namespace cppu;
+
+using com::sun::star::uno::Reference;
+
+
+// Implementation class SfxDialogLibraryContainer
+
+OUString SfxDialogLibraryContainer::getInfoFileName() const
+{
+ static constexpr OUStringLiteral dialog = u"dialog";
+ return dialog;
+}
+OUString SfxDialogLibraryContainer::getOldInfoFileName() const
+{
+ static constexpr OUStringLiteral dialogs = u"dialogs";
+ return dialogs;
+}
+OUString SfxDialogLibraryContainer::getLibElementFileExtension() const
+{
+ static constexpr OUStringLiteral xdl = u"xdl";
+ return xdl;
+}
+OUString SfxDialogLibraryContainer::getLibrariesDir() const
+{
+ static constexpr OUStringLiteral Dialogs = u"Dialogs";
+ return Dialogs;
+}
+
+// Ctor for service
+SfxDialogLibraryContainer::SfxDialogLibraryContainer()
+{
+ // all initialisation has to be done
+ // by calling XInitialization::initialize
+}
+
+SfxDialogLibraryContainer::SfxDialogLibraryContainer( const uno::Reference< embed::XStorage >& xStorage )
+{
+ init( OUString(), xStorage );
+}
+
+// Methods to get library instances of the correct type
+rtl::Reference<SfxLibrary> SfxDialogLibraryContainer::implCreateLibrary( const OUString& aName )
+{
+ return new SfxDialogLibrary( maModifiable, aName, mxSFI, this );
+}
+
+rtl::Reference<SfxLibrary> SfxDialogLibraryContainer::implCreateLibraryLink
+ ( const OUString& aName, const OUString& aLibInfoFileURL,
+ const OUString& StorageURL, bool ReadOnly )
+{
+ return new SfxDialogLibrary
+ ( maModifiable, aName, mxSFI, aLibInfoFileURL, StorageURL, ReadOnly, this );
+}
+
+Any SfxDialogLibraryContainer::createEmptyLibraryElement()
+{
+ Reference< XInputStreamProvider > xISP;
+ Any aRetAny;
+ aRetAny <<= xISP;
+ return aRetAny;
+}
+
+bool SfxDialogLibraryContainer::isLibraryElementValid(const Any& rElement) const
+{
+ return SfxDialogLibrary::containsValidDialog(rElement);
+}
+
+static bool writeOasis2OOoLibraryElement(
+ const Reference< XInputStream >& xInput, const Reference< XOutputStream >& xOutput )
+{
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+
+ Reference< lang::XMultiComponentFactory > xSMgr(
+ xContext->getServiceManager() );
+
+ Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(xContext);
+
+ Reference< xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
+
+ xWriter->setOutputStream( xOutput );
+
+ Sequence<Any> aArgs{ Any(xWriter) };
+ Reference< xml::sax::XDocumentHandler > xHandler(
+ xSMgr->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.Oasis2OOoTransformer",
+ aArgs, xContext ),
+ UNO_QUERY );
+
+ xParser->setDocumentHandler( xHandler );
+
+ xml::sax::InputSource source;
+ source.aInputStream = xInput;
+ source.sSystemId = "virtual file";
+
+ xParser->parseStream( source );
+
+ return true;
+}
+
+void SfxDialogLibraryContainer::writeLibraryElement
+(
+ const Reference < XNameContainer >& xLib,
+ const OUString& aElementName,
+ const Reference< XOutputStream >& xOutput
+)
+{
+ Any aElement = xLib->getByName( aElementName );
+ Reference< XInputStreamProvider > xISP;
+ aElement >>= xISP;
+ if( !xISP.is() )
+ return;
+
+ Reference< XInputStream > xInput( xISP->createInputStream() );
+
+ bool bComplete = false;
+ if ( mbOasis2OOoFormat )
+ {
+ bComplete = writeOasis2OOoLibraryElement( xInput, xOutput );
+ }
+
+ if ( !bComplete )
+ {
+ Sequence< sal_Int8 > bytes;
+ sal_Int32 nRead = xInput->readBytes( bytes, xInput->available() );
+ for (;;)
+ {
+ if( nRead )
+ xOutput->writeBytes( bytes );
+
+ nRead = xInput->readBytes( bytes, 1024 );
+ if (! nRead)
+ break;
+ }
+ }
+ xInput->closeInput();
+}
+
+void SfxDialogLibraryContainer::storeLibrariesToStorage( const uno::Reference< embed::XStorage >& xStorage )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ mbOasis2OOoFormat = false;
+
+ if ( mxStorage.is() && xStorage.is() )
+ {
+ try
+ {
+ tools::Long nSource = SotStorage::GetVersion( mxStorage );
+ tools::Long nTarget = SotStorage::GetVersion( xStorage );
+
+ if ( nSource == SOFFICE_FILEFORMAT_CURRENT &&
+ nTarget != SOFFICE_FILEFORMAT_CURRENT )
+ {
+ mbOasis2OOoFormat = true;
+ }
+ }
+ catch (const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("basic", "");
+ // if we cannot get the version then the
+ // Oasis2OOoTransformer will not be used
+ assert(false);
+ }
+ }
+
+ SfxLibraryContainer::storeLibrariesToStorage( xStorage );
+
+ // we need to export out any embedded image object(s)
+ // associated with any Dialogs. First, we need to actually gather any such urls
+ // for each dialog in this container
+ const Sequence< OUString > sLibraries = getElementNames();
+ for ( const OUString& rName : sLibraries )
+ {
+ loadLibrary( rName );
+ Reference< XNameContainer > xLib;
+ getByName( rName ) >>= xLib;
+ if ( xLib.is() )
+ {
+ Sequence< OUString > sDialogs = xLib->getElementNames();
+ sal_Int32 nDialogs( sDialogs.getLength() );
+ for ( sal_Int32 j=0; j < nDialogs; ++j )
+ {
+ // Each Dialog has an associated xISP
+ Reference< io::XInputStreamProvider > xISP;
+ xLib->getByName( sDialogs[ j ] ) >>= xISP;
+ if ( xISP.is() )
+ {
+ Reference< io::XInputStream > xInput( xISP->createInputStream() );
+ Reference< XNameContainer > xDialogModel(
+ mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", mxContext),
+ UNO_QUERY );
+ ::xmlscript::importDialogModel( xInput, xDialogModel, mxContext, mxOwnerDocument );
+ std::vector<uno::Reference<graphic::XGraphic>> vxGraphicList;
+ vcl::graphic::SearchForGraphics(Reference<XInterface>(xDialogModel, UNO_QUERY), vxGraphicList);
+ if (!vxGraphicList.empty())
+ {
+ // Export the images to the storage
+ Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ xGraphicStorageHandler.set(document::GraphicStorageHandler::createWithStorage(mxContext, xStorage));
+ if (xGraphicStorageHandler.is())
+ {
+ for (uno::Reference<graphic::XGraphic> const & rxGraphic : vxGraphicList)
+ {
+ xGraphicStorageHandler->saveGraphic(rxGraphic);
+ }
+ }
+ }
+ Reference< XComponent > xDialogModelComp(xDialogModel, UNO_QUERY);
+ if (xDialogModelComp)
+ xDialogModelComp->dispose();
+ }
+ }
+ }
+ }
+ mbOasis2OOoFormat = false;
+}
+
+
+Any SfxDialogLibraryContainer::importLibraryElement
+ ( const Reference < XNameContainer >& /*xLib*/,
+ const OUString& /*aElementName */, const OUString& aFile,
+ const uno::Reference< io::XInputStream >& xElementStream )
+{
+ Any aRetAny;
+
+ // TODO: Member because later it will be a component
+ //Reference< XMultiServiceFactory > xMSF( comphelper::getProcessServiceFactory() );
+ //if( !xMSF.is() )
+ //{
+ // OSL_FAIL( "### couldn't get ProcessServiceFactory" );
+ // return aRetAny;
+ //}
+
+ Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
+
+ Reference< XNameContainer > xDialogModel(
+ mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", mxContext),
+ UNO_QUERY );
+ if( !xDialogModel.is() )
+ {
+ OSL_FAIL( "### couldn't create com.sun.star.awt.UnoControlDialogModel component" );
+ return aRetAny;
+ }
+
+ // Read from storage?
+ bool bStorage = xElementStream.is();
+ Reference< XInputStream > xInput;
+
+ if( bStorage )
+ {
+ xInput = xElementStream;
+ }
+ else
+ {
+ try
+ {
+ xInput = mxSFI->openFileRead( aFile );
+ }
+ catch(const Exception& )
+ //catch( Exception& e )
+ {
+ // TODO:
+ //throw WrappedTargetException( e );
+ }
+ }
+ if( !xInput.is() )
+ return aRetAny;
+
+ InputSource source;
+ source.aInputStream = xInput;
+ source.sSystemId = aFile;
+
+ try {
+ // start parsing
+ xParser->setDocumentHandler( ::xmlscript::importDialogModel( xDialogModel, mxContext, mxOwnerDocument ) );
+ xParser->parseStream( source );
+ }
+ catch(const Exception& )
+ {
+ OSL_FAIL( "Parsing error" );
+ SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFile );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ return aRetAny;
+ }
+
+ // Create InputStream, TODO: Implement own InputStreamProvider
+ // to avoid creating the DialogModel here!
+ Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, mxContext, mxOwnerDocument );
+ aRetAny <<= xISP;
+
+ Reference< XComponent > xDialogModelComp(xDialogModel, UNO_QUERY);
+ if (xDialogModelComp)
+ xDialogModelComp->dispose();
+
+ return aRetAny;
+}
+
+void SfxDialogLibraryContainer::importFromOldStorage( const OUString& )
+{
+ // Nothing to do here, old dialogs cannot be imported
+}
+
+rtl::Reference<SfxLibraryContainer> SfxDialogLibraryContainer::createInstanceImpl()
+{
+ return new SfxDialogLibraryContainer();
+}
+
+constexpr OUStringLiteral aResourceFileNameBase = u"DialogStrings";
+constexpr OUStringLiteral aResourceFileCommentBase = u"# Strings for Dialog Library ";
+
+// Resource handling
+Reference< css::resource::XStringResourcePersistence >
+ SfxDialogLibraryContainer::implCreateStringResource( SfxDialogLibrary* pDialogLibrary )
+{
+ Reference< resource::XStringResourcePersistence > xRet;
+ OUString aLibName = pDialogLibrary->getName();
+ bool bReadOnly = pDialogLibrary->mbReadOnly;
+
+ // get ui locale
+ ::com::sun ::star::lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale();
+
+ OUString aComment= aResourceFileCommentBase + aLibName;
+
+ bool bStorage = mxStorage.is();
+ if( bStorage )
+ {
+ uno::Reference< embed::XStorage > xLibrariesStor;
+ uno::Reference< embed::XStorage > xLibraryStor;
+ try {
+ xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
+ // TODO: Should be READWRITE with new storage concept using store() instead of storeTo()
+ if ( !xLibrariesStor.is() )
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+
+ xLibraryStor = xLibrariesStor->openStorageElement( aLibName, embed::ElementModes::READ );
+ // TODO: Should be READWRITE with new storage concept using store() instead of storeTo()
+ if ( !xLibraryStor.is() )
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+ }
+ catch(const uno::Exception& )
+ {
+ // Something went wrong while trying to get the storage library.
+ // Return an object that supports StringResourceWithStorage, give it a storage location later.
+ xRet = Reference< resource::XStringResourcePersistence >(
+ mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.resource.StringResourceWithStorage", mxContext),
+ UNO_QUERY );
+ return xRet;
+ }
+
+ xRet = resource::StringResourceWithStorage::create(mxContext, xLibraryStor, bReadOnly, aLocale, aResourceFileNameBase, aComment);
+ }
+ else
+ {
+ OUString aLocation = createAppLibraryFolder( pDialogLibrary, aLibName );
+ // TODO: Real handler?
+ Reference< task::XInteractionHandler > xDummyHandler;
+
+ xRet = resource::StringResourceWithLocation::create(mxContext, aLocation, bReadOnly, aLocale, aResourceFileNameBase, aComment, xDummyHandler);
+ }
+
+ return xRet;
+}
+
+void SfxDialogLibraryContainer::onNewRootStorage()
+{
+ // 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 ];
+ SfxDialogLibrary* pDialogLibrary = static_cast<SfxDialogLibrary*>( getImplLib( aName ) );
+
+ Reference< resource::XStringResourcePersistence > xStringResourcePersistence =
+ pDialogLibrary->getStringResourcePersistence();
+
+ if( xStringResourcePersistence.is() )
+ {
+ Reference< embed::XStorage > xLibrariesStor;
+ Reference< embed::XStorage > xLibraryStor;
+ try {
+ xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READWRITE );
+ if ( !xLibrariesStor.is() )
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+
+ OUString aLibName = pDialogLibrary->getName();
+ xLibraryStor = xLibrariesStor->openStorageElement( aLibName, embed::ElementModes::READWRITE );
+ if ( !xLibraryStor.is() )
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+
+ Reference< resource::XStringResourceWithStorage >
+ xStringResourceWithStorage( xStringResourcePersistence, UNO_QUERY );
+ if( xStringResourceWithStorage.is() )
+ xStringResourceWithStorage->setStorage( xLibraryStor );
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: Error handling?
+ }
+ }
+ }
+}
+
+sal_Bool SAL_CALL
+SfxDialogLibraryContainer:: HasExecutableCode( const OUString& /*Library*/ )
+{
+ return false; // dialog library has no executable code
+}
+
+// Service
+
+OUString SAL_CALL SfxDialogLibraryContainer::getImplementationName( )
+{
+ return "com.sun.star.comp.sfx2.DialogLibraryContainer";
+}
+
+Sequence< OUString > SAL_CALL SfxDialogLibraryContainer::getSupportedServiceNames( )
+{
+ return {"com.sun.star.script.DocumentDialogLibraryContainer",
+ "com.sun.star.script.DialogLibraryContainer"}; // for compatibility
+}
+
+// Implementation class SfxDialogLibrary
+
+// Ctor
+SfxDialogLibrary::SfxDialogLibrary( ModifiableHelper& _rModifiable,
+ OUString aName,
+ const Reference< XSimpleFileAccess3 >& xSFI,
+ SfxDialogLibraryContainer* pParent )
+ : SfxLibrary( _rModifiable, cppu::UnoType<XInputStreamProvider>::get(), xSFI )
+ , m_pParent( pParent )
+ , m_aName(std::move( aName ))
+{
+}
+
+SfxDialogLibrary::SfxDialogLibrary( ModifiableHelper& _rModifiable,
+ OUString aName,
+ const Reference< XSimpleFileAccess3 >& xSFI,
+ const OUString& aLibInfoFileURL,
+ const OUString& aStorageURL,
+ bool ReadOnly,
+ SfxDialogLibraryContainer* pParent )
+ : SfxLibrary( _rModifiable, cppu::UnoType<XInputStreamProvider>::get(),
+ xSFI, aLibInfoFileURL, aStorageURL, ReadOnly)
+ , m_pParent( pParent )
+ , m_aName(std::move( aName ))
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SfxDialogLibrary, SfxLibrary, SfxDialogLibrary_BASE );
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SfxDialogLibrary, SfxLibrary, SfxDialogLibrary_BASE );
+
+// Provide modify state including resources
+bool SfxDialogLibrary::isModified()
+{
+ bool bRet = implIsModified();
+
+ if( !bRet && m_xStringResourcePersistence.is() )
+ bRet = m_xStringResourcePersistence->isModified();
+ // else: Resources not accessed so far -> not modified
+
+ return bRet;
+}
+
+void SfxDialogLibrary::storeResources()
+{
+ if( m_xStringResourcePersistence.is() )
+ m_xStringResourcePersistence->store();
+}
+
+void SfxDialogLibrary::storeResourcesAsURL
+ ( const OUString& URL, const OUString& NewName )
+{
+ OUString aComment(aResourceFileCommentBase);
+ m_aName = NewName;
+ aComment += m_aName;
+
+ if( m_xStringResourcePersistence.is() )
+ {
+ m_xStringResourcePersistence->setComment( aComment );
+
+ Reference< resource::XStringResourceWithLocation >
+ xStringResourceWithLocation( m_xStringResourcePersistence, UNO_QUERY );
+ if( xStringResourceWithLocation.is() )
+ xStringResourceWithLocation->storeAsURL( URL );
+ }
+}
+
+void SfxDialogLibrary::storeResourcesToURL( const OUString& URL,
+ const Reference< task::XInteractionHandler >& xHandler )
+{
+ OUString aComment = aResourceFileCommentBase + m_aName;
+
+ if( m_xStringResourcePersistence.is() )
+ {
+ m_xStringResourcePersistence->storeToURL
+ ( URL, aResourceFileNameBase, aComment, xHandler );
+ }
+}
+
+void SfxDialogLibrary::storeResourcesToStorage( const css::uno::Reference< css::embed::XStorage >& xStorage )
+{
+ OUString aComment = aResourceFileCommentBase + m_aName;
+
+ if( m_xStringResourcePersistence.is() )
+ {
+ m_xStringResourcePersistence->storeToStorage
+ ( xStorage, aResourceFileNameBase, aComment );
+ }
+}
+
+
+// XStringResourceSupplier
+Reference< resource::XStringResourceResolver >
+ SAL_CALL SfxDialogLibrary::getStringResource( )
+{
+ if( !m_xStringResourcePersistence.is() )
+ m_xStringResourcePersistence = m_pParent->implCreateStringResource( this );
+
+ return m_xStringResourcePersistence;
+}
+
+bool SfxDialogLibrary::containsValidDialog( const css::uno::Any& aElement )
+{
+ Reference< XInputStreamProvider > xISP;
+ aElement >>= xISP;
+ return xISP.is();
+}
+
+bool SfxDialogLibrary::isLibraryElementValid(const css::uno::Any& rElement) const
+{
+ return SfxDialogLibrary::containsValidDialog(rElement);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sfx2_DialogLibraryContainer_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new basic::SfxDialogLibraryContainer());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/source/uno/modsizeexceeded.cxx b/basic/source/uno/modsizeexceeded.cxx
new file mode 100644
index 000000000..27c795934
--- /dev/null
+++ b/basic/source/uno/modsizeexceeded.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <basic/modsizeexceeded.hxx>
+
+#include <comphelper/interaction.hxx>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/script/ModuleSizeExceededRequest.hpp>
+
+using namespace com::sun::star;
+using namespace cppu;
+using namespace osl;
+
+ModuleSizeExceeded::ModuleSizeExceeded(const std::vector<OUString>& sModules)
+{
+ script::ModuleSizeExceededRequest aReq;
+ aReq.Names = comphelper::containerToSequence(sModules);
+
+ m_aRequest <<= aReq;
+
+ m_xAbort = new comphelper::OInteractionAbort;
+ m_xApprove = new comphelper::OInteractionApprove;
+ m_lContinuations = { m_xApprove, m_xAbort };
+}
+
+bool ModuleSizeExceeded::isAbort() const
+{
+ comphelper::OInteractionAbort* pBase
+ = static_cast<comphelper::OInteractionAbort*>(m_xAbort.get());
+ return pBase->wasSelected();
+}
+
+bool ModuleSizeExceeded::isApprove() const
+{
+ comphelper::OInteractionApprove* pBase
+ = static_cast<comphelper::OInteractionApprove*>(m_xApprove.get());
+ return pBase->wasSelected();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/source/uno/namecont.cxx b/basic/source/uno/namecont.cxx
new file mode 100644
index 000000000..05a1a5b40
--- /dev/null
+++ b/basic/source/uno/namecont.cxx
@@ -0,0 +1,3498 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <config_extensions.h>
+#include <config_folders.h>
+
+#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/io/IOException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/errinf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sot/storage.hxx>
+#include <comphelper/getexpandeduri.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <namecont.hxx>
+#include <basic/basicmanagerrepository.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svtools/sfxecode.hxx>
+#include <svtools/ehdl.hxx>
+#include <basic/basmgr.hxx>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/io/XInputStream.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/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/util/PathSubstitution.hpp>
+#include <com/sun/star/deployment/ExtensionManager.hpp>
+#include <comphelper/storagehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <memory>
+#include <string_view>
+
+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 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()
+{
+ return mType;
+}
+
+sal_Bool NameContainer::hasElements()
+{
+ bool bRet = (mnElementCount > 0);
+ return bRet;
+}
+
+// Methods XNameAccess
+Any NameContainer::getByName( const OUString& aName )
+{
+ NameContainerNameMap::iterator aIt = mHashMap.find( aName );
+ if( aIt == mHashMap.end() )
+ {
+ throw NoSuchElementException();
+ }
+ sal_Int32 iHashResult = (*aIt).second;
+ Any aRetAny = mValues[ iHashResult ];
+ return aRetAny;
+}
+
+Sequence< OUString > NameContainer::getElementNames()
+{
+ return comphelper::containerToSequence(mNames);
+}
+
+sal_Bool NameContainer::hasByName( const OUString& aName )
+{
+ NameContainerNameMap::iterator aIt = mHashMap.find( aName );
+ bool bRet = ( aIt != mHashMap.end() );
+ return bRet;
+}
+
+
+// Methods XNameReplace
+void NameContainer::replaceByName( const OUString& aName, const Any& aElement )
+{
+ const Type& aAnyType = aElement.getValueType();
+ if( mType != aAnyType )
+ {
+ throw IllegalArgumentException("types do not match", static_cast<cppu::OWeakObject*>(this), 2);
+ }
+ NameContainerNameMap::iterator aIt = mHashMap.find( aName );
+ if( aIt == mHashMap.end() )
+ {
+ throw NoSuchElementException();
+ }
+ sal_Int32 iHashResult = (*aIt).second;
+ Any aOldElement = mValues[ iHashResult ];
+ mValues[ 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 on 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 = { { Any(aName), aElement, aOldElement } };
+ maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
+ }
+}
+
+void NameContainer::insertCheck(const OUString& aName, const Any& aElement)
+{
+ NameContainerNameMap::iterator aIt = mHashMap.find(aName);
+ if( aIt != mHashMap.end() )
+ {
+ throw ElementExistException();
+ }
+ insertNoCheck(aName, aElement);
+}
+
+void NameContainer::insertNoCheck(const OUString& aName, const Any& aElement)
+{
+ const Type& aAnyType = aElement.getValueType();
+ if( mType != aAnyType )
+ {
+ throw IllegalArgumentException("types do not match", static_cast<cppu::OWeakObject*>(this), 2);
+ }
+
+ sal_Int32 nCount = mNames.size();
+ mNames.push_back( aName );
+ mValues.push_back( 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 on 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 = { { Any(aName), aElement, {} } };
+ maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
+ }
+}
+
+// Methods XNameContainer
+void NameContainer::insertByName( const OUString& aName, const Any& aElement )
+{
+ insertCheck(aName, aElement);
+}
+
+void NameContainer::removeByName( const OUString& aName )
+{
+ NameContainerNameMap::iterator aIt = mHashMap.find( aName );
+ if( aIt == mHashMap.end() )
+ {
+ OUString sMessage = "\"" + aName + "\" not found";
+ throw NoSuchElementException(sMessage);
+ }
+
+ sal_Int32 iHashResult = (*aIt).second;
+ Any aOldElement = mValues[ iHashResult ];
+ mHashMap.erase( aIt );
+ sal_Int32 iLast = mNames.size() - 1;
+ if( iLast != iHashResult )
+ {
+ mNames[ iHashResult ] = mNames[ iLast ];
+ mValues[ iHashResult ] = mValues[ iLast ];
+ mHashMap[ mNames[ iHashResult ] ] = iHashResult;
+ }
+ mNames.resize( iLast );
+ mValues.resize( 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 on 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 = { { Any(aName),
+ {}, // Element remains empty (meaning "replaced with nothing")
+ aOldElement } };
+ maChangesListeners.notifyEach( &XChangesListener::changesOccurred, aEvent );
+ }
+}
+
+
+// Methods XContainer
+void SAL_CALL NameContainer::addContainerListener( const Reference< XContainerListener >& xListener )
+{
+ if( !xListener.is() )
+ {
+ throw RuntimeException("addContainerListener called with null xListener",static_cast< cppu::OWeakObject * >(this));
+ }
+ maContainerListeners.addInterface( xListener );
+}
+
+void SAL_CALL NameContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
+{
+ if( !xListener.is() )
+ {
+ throw RuntimeException("removeContainerListener called with null xListener",static_cast< cppu::OWeakObject * >(this));
+ }
+ maContainerListeners.removeInterface( xListener );
+}
+
+// Methods XChangesNotifier
+void SAL_CALL NameContainer::addChangesListener( const Reference< XChangesListener >& xListener )
+{
+ if( !xListener.is() )
+ {
+ throw RuntimeException("addChangesListener called with null xListener",static_cast< cppu::OWeakObject * >(this));
+ }
+ maChangesListeners.addInterface( xListener );
+}
+
+void SAL_CALL NameContainer::removeChangesListener( const Reference< XChangesListener >& xListener )
+{
+ if( !xListener.is() )
+ {
+ throw RuntimeException("removeChangesListener called with null xListener",static_cast< cppu::OWeakObject * >(this));
+ }
+ maChangesListeners.removeInterface( xListener );
+}
+
+
+// ModifiableHelper
+
+void ModifiableHelper::setModified( bool _bModified )
+{
+ if ( _bModified == mbModified )
+ {
+ return;
+ }
+ mbModified = _bModified;
+
+ if ( m_aModifyListeners.getLength() == 0 )
+ {
+ return;
+ }
+ EventObject aModifyEvent( m_rEventSource );
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, aModifyEvent );
+}
+
+
+// Ctor
+SfxLibraryContainer::SfxLibraryContainer()
+ : SfxLibraryContainer_BASE( m_aMutex )
+ , maVBAScriptListeners( m_aMutex )
+ , mnRunningVBAScripts( 0 )
+ , mbVBACompat( false )
+ , meVBATextEncoding( RTL_TEXTENCODING_DONTKNOW )
+ , maModifiable( *this, m_aMutex )
+ , maNameContainer( new NameContainer(cppu::UnoType<XNameAccess>::get()) )
+ , mbOldInfoFormat( false )
+ , mbOasis2OOoFormat( false )
+ , mpBasMgr( nullptr )
+ , mbOwnBasMgr( false )
+ , meInitMode(DEFAULT)
+{
+ mxContext = comphelper::getProcessComponentContext();
+
+ mxSFI = ucb::SimpleFileAccess::create( mxContext );
+
+ mxStringSubstitution = util::PathSubstitution::create( mxContext );
+}
+
+SfxLibraryContainer::~SfxLibraryContainer()
+{
+ if( mbOwnBasMgr )
+ {
+ delete mpBasMgr;
+ }
+}
+
+void SfxLibraryContainer::enterMethod()
+{
+ Application::GetSolarMutex().acquire();
+ if ( rBHelper.bInDispose || rBHelper.bDisposed )
+ {
+ throw DisposedException( OUString(), *this );
+ }
+}
+
+void SfxLibraryContainer::leaveMethod()
+{
+ Application::GetSolarMutex().release();
+}
+
+BasicManager* SfxLibraryContainer::getBasicManager()
+{
+ try
+ {
+ if ( mpBasMgr )
+ {
+ return mpBasMgr;
+ }
+ Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
+ SAL_WARN_IF(
+ !xDocument.is(), "basic",
+ ("SfxLibraryContainer::getBasicManager: cannot obtain a BasicManager"
+ " without document!"));
+ if ( xDocument.is() )
+ {
+ mpBasMgr = BasicManagerRepository::getDocumentBasicManager( xDocument );
+ }
+ }
+ catch (const css::ucb::ContentCreationException&)
+ {
+ TOOLS_WARN_EXCEPTION( "basic", "SfxLibraryContainer::getBasicManager:" );
+ }
+ return mpBasMgr;
+}
+
+// Methods XStorageBasedLibraryContainer
+Reference< XStorage > SAL_CALL SfxLibraryContainer::getRootStorage()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return mxStorage;
+}
+
+void SAL_CALL SfxLibraryContainer::setRootStorage( const Reference< XStorage >& _rxRootStorage )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ if ( !_rxRootStorage.is() )
+ {
+ throw IllegalArgumentException("no root storage", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ mxStorage = _rxRootStorage;
+ onNewRootStorage();
+}
+
+void SAL_CALL SfxLibraryContainer::storeLibrariesToStorage( const Reference< XStorage >& _rxRootStorage )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ if ( !_rxRootStorage.is() )
+ {
+ throw IllegalArgumentException("no root storage", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ try
+ {
+ storeLibraries_Impl( _rxRootStorage, true );
+ }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( OUString(),
+ *this, ::cppu::getCaughtException() );
+ }
+}
+
+
+// Methods XModifiable
+sal_Bool SfxLibraryContainer::isModified()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ if ( maModifiable.isModified() )
+ {
+ return 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 ];
+ try
+ {
+ SfxLibrary* pImplLib = getImplLib( aName );
+ if( pImplLib->isModified() )
+ {
+ if ( aName == "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 true;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ catch(const css::container::NoSuchElementException&)
+ {
+ }
+ }
+
+ return false;
+}
+
+void SAL_CALL SfxLibraryContainer::setModified( sal_Bool _bModified )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ maModifiable.setModified( _bModified );
+}
+
+void SAL_CALL SfxLibraryContainer::addModifyListener( const Reference< XModifyListener >& _rxListener )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ maModifiable.addModifyListener( _rxListener );
+}
+
+void SAL_CALL SfxLibraryContainer::removeModifyListener( const Reference< XModifyListener >& _rxListener )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ maModifiable.removeModifyListener( _rxListener );
+}
+
+// Methods XPersistentLibraryContainer
+Any SAL_CALL SfxLibraryContainer::getRootLocation()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return Any( getRootStorage() );
+}
+
+OUString SAL_CALL SfxLibraryContainer::getContainerLocationName()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return maLibrariesDir;
+}
+
+void SAL_CALL SfxLibraryContainer::storeLibraries( )
+{
+ 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( OUString(), *this, ::cppu::getCaughtException() );
+ }
+}
+
+static void checkAndCopyFileImpl( const INetURLObject& rSourceFolderInetObj,
+ const INetURLObject& rTargetFolderInetObj,
+ std::u16string_view rCheckFileName,
+ std::u16string_view rCheckExtension,
+ const Reference< XSimpleFileAccess3 >& xSFI )
+{
+ INetURLObject aTargetFolderInetObj( rTargetFolderInetObj );
+ aTargetFolderInetObj.insertName( rCheckFileName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aTargetFolderInetObj.setExtension( rCheckExtension );
+ OUString aTargetFile = aTargetFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( !xSFI->exists( aTargetFile ) )
+ {
+ INetURLObject aSourceFolderInetObj( rSourceFolderInetObj );
+ aSourceFolderInetObj.insertName( rCheckFileName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aSourceFolderInetObj.setExtension( rCheckExtension );
+ OUString aSourceFile = aSourceFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ xSFI->copy( aSourceFile, aTargetFile );
+ }
+}
+
+static void createVariableURL( OUString& rStr, std::u16string_view rLibName,
+ std::u16string_view rInfoFileName, bool bUser )
+{
+ if( bUser )
+ {
+ rStr = "$(USER)/basic/";
+ }
+ else
+ {
+ rStr = "$(INST)/" LIBO_SHARE_FOLDER "/basic/";
+ }
+ rStr += OUString::Concat(rLibName) + "/" + rInfoFileName + ".xlb/";
+}
+
+void 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
+ // a UNO reference to ourself.
+ // Ensure that we're not destroyed while we're in here
+ osl_atomic_increment( &m_refCount );
+ init_Impl( rInitialDocumentURL, rxInitialStorage );
+ osl_atomic_decrement( &m_refCount );
+}
+
+void SfxLibraryContainer::init_Impl( const OUString& rInitialDocumentURL,
+ const uno::Reference< embed::XStorage >& rxInitialStorage )
+{
+ uno::Reference< embed::XStorage > xStorage = rxInitialStorage;
+
+ maInitialDocumentURL = rInitialDocumentURL;
+ maInfoFileName = getInfoFileName();
+ maOldInfoFileName = getOldInfoFileName();
+ maLibElementFileExtension = getLibElementFileExtension();
+ maLibrariesDir = getLibrariesDir();
+
+ meInitMode = DEFAULT;
+ INetURLObject aInitUrlInetObj( maInitialDocumentURL );
+ OUString aInitFileName = aInitUrlInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( !aInitFileName.isEmpty() )
+ {
+ // We need a BasicManager to avoid problems
+ StarBASIC* pBas = new StarBASIC();
+ mpBasMgr = new BasicManager( pBas );
+ mbOwnBasMgr = true;
+
+ OUString aExtension = aInitUrlInetObj.getExtension();
+ if( aExtension == "xlc" )
+ {
+ meInitMode = CONTAINER_INIT_FILE;
+ INetURLObject aLibPathInetObj( aInitUrlInetObj );
+ aLibPathInetObj.removeSegment();
+ maLibraryPath = aLibPathInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ else if( aExtension == "xlb" )
+ {
+ meInitMode = LIBRARY_INIT_FILE;
+ uno::Reference< embed::XStorage > xDummyStor;
+ ::xmlscript::LibDescriptor aLibDesc;
+ implLoadLibraryIndexFile( nullptr, aLibDesc, xDummyStor, aInitFileName );
+ return;
+ }
+ else
+ {
+ // Decide between old and new document
+ bool bOldStorage = SotStorage::IsOLEStorage( aInitFileName );
+ if ( bOldStorage )
+ {
+ meInitMode = OLD_BASIC_STORAGE;
+ importFromOldStorage( aInitFileName );
+ return;
+ }
+ else
+ {
+ meInitMode = OFFICE_DOCUMENT;
+ try
+ {
+ xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( aInitFileName, embed::ElementModes::READ );
+ }
+ catch (const uno::Exception& )
+ {
+ // TODO: error handling
+ }
+ }
+ }
+ }
+ else
+ {
+ // Default paths
+ maLibraryPath = SvtPathOptions().GetBasicPath();
+ }
+
+ uno::Reference< io::XInputStream > xInput;
+
+ mxStorage = xStorage;
+ bool bStorage = mxStorage.is();
+
+
+ // #110009: Scope to force the StorageRefs to be destructed and
+ // so the streams to be closed before the preload operation
+ {
+
+ uno::Reference< embed::XStorage > xLibrariesStor;
+ OUString aFileName;
+
+ int nPassCount = 1;
+ if( !bStorage && meInitMode == DEFAULT )
+ {
+ nPassCount = 2;
+ }
+ for( int nPass = 0 ; nPass < nPassCount ; nPass++ )
+ {
+ if( bStorage )
+ {
+ SAL_WARN_IF(
+ meInitMode != DEFAULT && meInitMode != OFFICE_DOCUMENT, "basic",
+ "Wrong InitMode for document");
+ try
+ {
+ uno::Reference< io::XStream > xStream;
+ xLibrariesStor = xStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
+
+ if ( xLibrariesStor.is() )
+ {
+ aFileName = maInfoFileName + "-lc.xml";
+ try
+ {
+ xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
+ }
+ catch(const uno::Exception& )
+ {}
+
+ if( !xStream.is() )
+ {
+ mbOldInfoFormat = true;
+
+ // Check old version
+ aFileName = maOldInfoFileName + ".xml";
+ try
+ {
+ xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
+ }
+ catch(const uno::Exception& )
+ {}
+
+ if( !xStream.is() )
+ {
+ // Check for EA2 document version with wrong extensions
+ aFileName = maOldInfoFileName + ".xli";
+ xStream = xLibrariesStor->openStreamElement( aFileName, embed::ElementModes::READ );
+ }
+ }
+ }
+
+ if ( xStream.is() )
+ {
+ xInput = xStream->getInputStream();
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: error handling?
+ }
+ }
+ else
+ {
+ std::unique_ptr<INetURLObject> pLibInfoInetObj;
+ if( meInitMode == CONTAINER_INIT_FILE )
+ {
+ aFileName = aInitFileName;
+ }
+ else
+ {
+ if( nPass == 1 )
+ {
+ pLibInfoInetObj.reset(new INetURLObject( o3tl::getToken(maLibraryPath, 0, ';') ));
+ }
+ else
+ {
+ pLibInfoInetObj.reset(new INetURLObject( o3tl::getToken(maLibraryPath, 1, ';') ));
+ }
+ pLibInfoInetObj->insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ pLibInfoInetObj->setExtension( u"xlc" );
+ aFileName = pLibInfoInetObj->GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+
+ try
+ {
+ xInput = mxSFI->openFileRead( aFileName );
+ }
+ catch(const Exception& )
+ {
+ // Silently tolerate empty or missing files
+ xInput.clear();
+ }
+
+ // Old variant?
+ if( !xInput.is() && nPass == 0 )
+ {
+ INetURLObject aLibInfoInetObj( o3tl::getToken(maLibraryPath, 1, ';') );
+ aLibInfoInetObj.insertName( maOldInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aLibInfoInetObj.setExtension( u"xli" );
+ aFileName = aLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ try
+ {
+ xInput = mxSFI->openFileRead( aFileName );
+ mbOldInfoFormat = true;
+ }
+ catch(const Exception& )
+ {
+ xInput.clear();
+ }
+ }
+ }
+
+ if( xInput.is() )
+ {
+ InputSource source;
+ source.aInputStream = xInput;
+ source.sSystemId = aFileName;
+
+ // start parsing
+ auto pLibArray = std::make_unique<::xmlscript::LibDescriptorArray> ( );
+
+ Reference< XParser > xParser = xml::sax::Parser::create(mxContext);
+ try
+ {
+ xParser->setDocumentHandler( ::xmlscript::importLibraryContainer( pLibArray.get() ) );
+ xParser->parseStream( source );
+ }
+ catch ( const xml::sax::SAXException& )
+ {
+ TOOLS_WARN_EXCEPTION( "basic", "" );
+ return;
+ }
+ catch ( const io::IOException& )
+ {
+ TOOLS_WARN_EXCEPTION( "basic", "" );
+ return;
+ }
+
+ 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.isEmpty() && nPass == 0 )
+ {
+ OUString aLibraryPath;
+ if( meInitMode == CONTAINER_INIT_FILE )
+ {
+ aLibraryPath = maLibraryPath;
+ }
+ else
+ {
+ aLibraryPath = maLibraryPath.getToken(1, ';');
+ }
+ INetURLObject aInetObj( aLibraryPath );
+
+ aInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( mxSFI->isFolder( aLibDirPath ) )
+ {
+ createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, true );
+ maModifiable.setModified( true );
+ }
+ else if( rLib.bLink )
+ {
+ // Check "share" path
+ INetURLObject aShareInetObj( o3tl::getToken(maLibraryPath, 0, ';') );
+ aShareInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ OUString aShareLibDirPath = aShareInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( mxSFI->isFolder( aShareLibDirPath ) )
+ {
+ createVariableURL( rLib.aStorageURL, rLib.aName, maInfoFileName, false );
+ maModifiable.setModified( 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 = false;
+ pImplLib->mbReadOnly = rLib.bReadOnly;
+ if( !bStorage )
+ {
+ checkStorageURL( rLib.aStorageURL, pImplLib->maLibInfoFileURL,
+ pImplLib->maStorageURL, pImplLib->maUnexpandedStorageURL );
+ }
+ }
+ maModifiable.setModified( 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(const uno::Exception& )
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ TOOLS_WARN_EXCEPTION(
+ "basic",
+ "couldn't open sub storage for library \"" << rLib.aName << "\"");
+ #endif
+ }
+ }
+
+ // Link is already initialised in createLibraryLink()
+ if( !pImplLib->mbInitialised && (!bStorage || xLibraryStor.is()) )
+ {
+ bool bLoaded = implLoadLibraryIndexFile( pImplLib, rLib, xLibraryStor, OUString() );
+ SAL_WARN_IF(
+ bLoaded && aLibName != rLib.aName, "basic",
+ ("Different library names in library container and"
+ " library info files!"));
+ 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 = true;
+ pImplLib->mbReadOnly = true;
+ }
+ }
+
+ // Keep flag for documents to force writing the new index files
+ if( !bStorage )
+ {
+ mbOldInfoFormat = false;
+ }
+ }
+ }
+
+ // #110009: END Scope to force the StorageRefs to be destructed
+ }
+
+ if( !bStorage && meInitMode == DEFAULT )
+ {
+ try
+ {
+ implScanExtensions();
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: error handling?
+ SAL_WARN("basic", "Cannot access extensions!");
+ }
+ }
+
+ // 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 );
+ }
+ }
+ }
+
+ if( meInitMode != DEFAULT )
+ return;
+
+ // tdf#121740 speed up loading documents with lots of embedded documents by avoid the UCB work of updating non-existent VBA libraries
+ if (rInitialDocumentURL.isEmpty())
+ return;
+
+ INetURLObject aUserBasicInetObj( o3tl::getToken(maLibraryPath, 1, ';') );
+ OUString aStandardStr("Standard");
+
+ INetURLObject aPrevUserBasicInetObj_1( aUserBasicInetObj );
+ aPrevUserBasicInetObj_1.removeSegment();
+ INetURLObject aPrevUserBasicInetObj_2 = aPrevUserBasicInetObj_1;
+ aPrevUserBasicInetObj_1.Append( u"__basic_80" );
+ aPrevUserBasicInetObj_2.Append( u"__basic_80_2" );
+
+ // #i93163
+ bool bCleanUp = false;
+ try
+ {
+ INetURLObject aPrevUserBasicInetObj = aPrevUserBasicInetObj_1;
+ OUString aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( mxSFI->isFolder( aPrevFolder ) )
+ {
+ // Check if Standard folder exists and is complete
+ INetURLObject aUserBasicStandardInetObj( aUserBasicInetObj );
+ aUserBasicStandardInetObj.insertName( aStandardStr, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ INetURLObject aPrevUserBasicStandardInetObj( aPrevUserBasicInetObj );
+ aPrevUserBasicStandardInetObj.insertName( aStandardStr, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ OUString aPrevStandardFolder = aPrevUserBasicStandardInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( mxSFI->isFolder( aPrevStandardFolder ) )
+ {
+ OUString aXlbExtension( "xlb" );
+ OUString aCheckFileName;
+
+ // Check if script.xlb exists
+ aCheckFileName = "script";
+ checkAndCopyFileImpl( aUserBasicStandardInetObj,
+ aPrevUserBasicStandardInetObj,
+ aCheckFileName, aXlbExtension, mxSFI );
+
+ // Check if dialog.xlb exists
+ aCheckFileName = "dialog";
+ checkAndCopyFileImpl( aUserBasicStandardInetObj,
+ aPrevUserBasicStandardInetObj,
+ aCheckFileName, aXlbExtension, mxSFI );
+
+ // Check if module1.xba exists
+ aCheckFileName = "Module1";
+ checkAndCopyFileImpl( aUserBasicStandardInetObj,
+ aPrevUserBasicStandardInetObj,
+ aCheckFileName, u"xba", mxSFI );
+ }
+ else
+ {
+ OUString aStandardFolder = aUserBasicStandardInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ mxSFI->copy( aStandardFolder, aPrevStandardFolder );
+ }
+
+ OUString aPrevCopyToFolder = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ mxSFI->copy( aPrevFolder, aPrevCopyToFolder );
+ }
+ else
+ {
+ aPrevUserBasicInetObj = aPrevUserBasicInetObj_2;
+ aPrevFolder = aPrevUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ if( mxSFI->isFolder( aPrevFolder ) )
+ {
+ rtl::Reference<SfxLibraryContainer> pPrevCont = createInstanceImpl();
+
+ // Rename previous basic folder to make storage URLs correct during initialisation
+ OUString aFolderUserBasic = aUserBasicInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ INetURLObject aUserBasicTmpInetObj( aUserBasicInetObj );
+ aUserBasicTmpInetObj.removeSegment();
+ aUserBasicTmpInetObj.Append( u"__basic_tmp" );
+ OUString aFolderTmp = aUserBasicTmpInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ mxSFI->move( aFolderUserBasic, aFolderTmp );
+ try
+ {
+ mxSFI->move( aPrevFolder, aFolderUserBasic );
+ }
+ catch(const Exception& )
+ {
+ // Move back user/basic folder
+ try
+ {
+ mxSFI->kill( aFolderUserBasic );
+ }
+ catch(const Exception& )
+ {}
+ mxSFI->move( aFolderTmp, aFolderUserBasic );
+ throw;
+ }
+
+ INetURLObject aPrevUserBasicLibInfoInetObj( aUserBasicInetObj );
+ aPrevUserBasicLibInfoInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aPrevUserBasicLibInfoInetObj.setExtension( u"xlc");
+ OUString aLibInfoFileName = aPrevUserBasicLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ 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 );
+
+ 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 );
+ OUString 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( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE" ) != -1 ||
+ aStorageURL.indexOf( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" ) != -1 ||
+ aStorageURL.indexOf( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" ) != -1 ||
+ aStorageURL.indexOf( "$(INST)" ) != -1 )
+ {
+ bCreateLink = false;
+ }
+ if( bCreateLink )
+ {
+ createLibraryLink( aLibName, pImplLib->maStorageURL, pImplLib->mbReadOnly );
+ }
+ }
+ else
+ {
+ // Move folder if not already done
+ INetURLObject aUserBasicLibFolderInetObj( aUserBasicInetObj );
+ aUserBasicLibFolderInetObj.Append( aLibName );
+ OUString aLibFolder = aUserBasicLibFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ INetURLObject aPrevUserBasicLibFolderInetObj( aPrevUserBasicInetObj );
+ aPrevUserBasicLibFolderInetObj.Append( aLibName );
+ OUString aPrevLibFolder = aPrevUserBasicLibFolderInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ 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( false );
+ checkStorageURL( aLibFolder, pNewLib->maLibInfoFileURL,
+ pNewLib->maStorageURL, pNewLib->maUnexpandedStorageURL );
+
+ uno::Reference< embed::XStorage > xDummyStor;
+ ::xmlscript::LibDescriptor aLibDesc;
+ implLoadLibraryIndexFile( pNewLib, aLibDesc, xDummyStor, pNewLib->maLibInfoFileURL );
+ implImportLibDescriptor( pNewLib, aLibDesc );
+ }
+ }
+ mxSFI->kill( aPrevFolder );
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("basic", "Upgrade of Basic installation failed somehow" );
+ bCleanUp = true;
+ }
+
+ // #i93163
+ if( !bCleanUp )
+ return;
+
+ INetURLObject aPrevUserBasicInetObj_Err( aUserBasicInetObj );
+ aPrevUserBasicInetObj_Err.removeSegment();
+ aPrevUserBasicInetObj_Err.Append( u"__basic_80_err" );
+ OUString aPrevFolder_Err = aPrevUserBasicInetObj_Err.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ bool bSaved = false;
+ try
+ {
+ OUString aPrevFolder_1 = aPrevUserBasicInetObj_1.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( mxSFI->isFolder( aPrevFolder_1 ) )
+ {
+ mxSFI->move( aPrevFolder_1, aPrevFolder_Err );
+ bSaved = true;
+ }
+ }
+ catch(const Exception& )
+ {}
+ try
+ {
+ OUString aPrevFolder_2 = aPrevUserBasicInetObj_2.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( !bSaved && mxSFI->isFolder( aPrevFolder_2 ) )
+ {
+ mxSFI->move( aPrevFolder_2, aPrevFolder_Err );
+ }
+ else
+ {
+ mxSFI->kill( aPrevFolder_2 );
+ }
+ }
+ catch(const Exception& )
+ {}
+}
+
+void SfxLibraryContainer::implScanExtensions()
+{
+#if HAVE_FEATURE_EXTENSIONS
+ ScriptExtensionIterator aScriptIt;
+
+ bool bPureDialogLib = false;
+ for (;;)
+ {
+ OUString aLibURL = aScriptIt.nextBasicOrDialogLibrary( bPureDialogLib );
+ if (aLibURL.isEmpty())
+ break;
+ if( bPureDialogLib && maInfoFileName == "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 += "/";
+ }
+ aIndexFileURL += maInfoFileName + ".xlb";
+
+ // Create link
+ const bool bReadOnly = false;
+ createLibraryLink( aLibName, aIndexFileURL, bReadOnly );
+ }
+#else
+ (void) this;
+#endif
+}
+
+// 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 == "xlb" )
+ {
+ // URL to xlb file
+ aLibInfoFileURL = aExpandedSourceURL;
+ aInetObj.removeSegment();
+ aStorageURL = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ else
+ {
+ // URL to library folder
+ aStorageURL = aExpandedSourceURL;
+ aInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aInetObj.setExtension( u"xlb" );
+ aLibInfoFileURL = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+}
+
+SfxLibrary* SfxLibraryContainer::getImplLib( const OUString& 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 unnecessary implementation in dlgcont.cxx
+bool SfxLibraryContainer::implStorePasswordLibrary( SfxLibrary*,
+ const OUString&,
+ const uno::Reference< embed::XStorage >&,
+ const uno::Reference< task::XInteractionHandler >& )
+{
+ return false;
+}
+
+bool SfxLibraryContainer::implStorePasswordLibrary(
+ SfxLibrary* /*pLib*/,
+ const OUString& /*aName*/,
+ const css::uno::Reference< css::embed::XStorage >& /*xStorage*/,
+ const OUString& /*aTargetURL*/,
+ const Reference< XSimpleFileAccess3 >& /*xToUseSFI*/,
+ const uno::Reference< task::XInteractionHandler >& )
+{
+ return false;
+}
+
+bool SfxLibraryContainer::implLoadPasswordLibrary(
+ SfxLibrary* /*pLib*/,
+ const OUString& /*Name*/,
+ bool /*bVerifyPasswordOnly*/ )
+{
+ return true;
+}
+
+OUString SfxLibraryContainer::createAppLibraryFolder( SfxLibrary* pLib, std::u16string_view aName )
+{
+ OUString aLibDirPath = pLib->maStorageURL;
+ if( aLibDirPath.isEmpty() )
+ {
+ INetURLObject aInetObj( o3tl::getToken(maLibraryPath, 1, ';') );
+ aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ checkStorageURL( aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), pLib->maLibInfoFileURL,
+ pLib->maStorageURL, pLib->maUnexpandedStorageURL );
+ aLibDirPath = pLib->maStorageURL;
+ }
+
+ if( !mxSFI->isFolder( aLibDirPath ) )
+ {
+ try
+ {
+ mxSFI->createFolder( aLibDirPath );
+ }
+ catch(const Exception& )
+ {}
+ }
+
+ return aLibDirPath;
+}
+
+// Storing
+void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
+ std::u16string_view aName,
+ const uno::Reference< embed::XStorage >& xStorage )
+{
+ Reference< XSimpleFileAccess3 > xDummySFA;
+ Reference< XInteractionHandler > xDummyHandler;
+ implStoreLibrary( pLib, aName, xStorage, u"", xDummySFA, xDummyHandler );
+}
+
+// New variant for library export
+void SfxLibraryContainer::implStoreLibrary( SfxLibrary* pLib,
+ std::u16string_view aName,
+ const uno::Reference< embed::XStorage >& xStorage,
+ std::u16string_view aTargetURL,
+ const Reference< XSimpleFileAccess3 >& rToUseSFI,
+ const Reference< XInteractionHandler >& xHandler )
+{
+ bool bLink = pLib->mbLink;
+ 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 + ".xml";
+
+ if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
+ {
+ SAL_WARN(
+ "basic",
+ "invalid library element \"" << aElementName << '"');
+ continue;
+ }
+ try
+ {
+ uno::Reference< io::XStream > xElementStream = xStorage->openStreamElement(
+ aStreamName,
+ embed::ElementModes::READWRITE );
+ // throw uno::RuntimeException(); // TODO: method must either return the stream or throw an exception
+
+ uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY );
+ SAL_WARN_IF(
+ !xProps.is(), "basic",
+ "The StorageStream must implement XPropertySet interface!");
+ //if ( !xProps.is() ) //TODO
+
+ if ( xProps.is() )
+ {
+ xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
+
+ // #87671 Allow encryption
+ xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
+
+ Reference< XOutputStream > xOutput = xElementStream->getOutputStream();
+ Reference< XNameContainer > xLib( pLib );
+ writeLibraryElement( xLib, aElementName, xOutput );
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ SAL_WARN("basic", "Problem during storing of library!");
+ // TODO: error handling?
+ }
+ }
+ pLib->storeResourcesToStorage( xStorage );
+ }
+ else
+ {
+ // Export?
+ bool bExport = !aTargetURL.empty();
+ try
+ {
+ Reference< XSimpleFileAccess3 > xSFI = mxSFI;
+ if( rToUseSFI.is() )
+ {
+ xSFI = rToUseSFI;
+ }
+ OUString aLibDirPath;
+ if( bExport )
+ {
+ INetURLObject aInetObj( aTargetURL );
+ aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ 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, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( maLibElementFileExtension );
+ OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
+ {
+ SAL_WARN(
+ "basic",
+ "invalid library element \"" << aElementName << '"');
+ 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(const Exception& )
+ {
+ if( bExport )
+ {
+ throw;
+ }
+ SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aElementPath );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ if( bExport )
+ {
+ throw;
+ }
+ }
+ }
+}
+
+void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
+ const ::xmlscript::LibDescriptor& rLib,
+ const uno::Reference< embed::XStorage >& xStorage )
+{
+ Reference< XSimpleFileAccess3 > xDummySFA;
+ implStoreLibraryIndexFile( pLib, rLib, xStorage, u"", xDummySFA );
+}
+
+// New variant for library export
+void SfxLibraryContainer::implStoreLibraryIndexFile( SfxLibrary* pLib,
+ const ::xmlscript::LibDescriptor& rLib,
+ const uno::Reference< embed::XStorage >& xStorage,
+ std::u16string_view aTargetURL,
+ const Reference< XSimpleFileAccess3 >& rToUseSFI )
+{
+ // Create sax writer
+ Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
+
+ bool bLink = pLib->mbLink;
+ bool bStorage = xStorage.is() && !bLink;
+
+ // Write info file
+ uno::Reference< io::XOutputStream > xOut;
+ uno::Reference< io::XStream > xInfoStream;
+ if( bStorage )
+ {
+ OUString aStreamName = maInfoFileName + "-lb.xml";
+
+ try
+ {
+ xInfoStream = xStorage->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
+ SAL_WARN_IF(!xInfoStream.is(), "basic", "No stream!");
+ uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY );
+ // throw uno::RuntimeException(); // TODO
+
+ if ( xProps.is() )
+ {
+ xProps->setPropertyValue("MediaType", uno::Any( OUString("text/xml") ) );
+
+ // #87671 Allow encryption
+ xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
+
+ xOut = xInfoStream->getOutputStream();
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ SAL_WARN("basic", "Problem during storing of library index file!");
+ // TODO: error handling?
+ }
+ }
+ else
+ {
+ // Export?
+ bool bExport = !aTargetURL.empty();
+ Reference< XSimpleFileAccess3 > xSFI = mxSFI;
+ if( rToUseSFI.is() )
+ {
+ xSFI = rToUseSFI;
+ }
+ OUString aLibInfoPath;
+ if( bExport )
+ {
+ INetURLObject aInetObj( aTargetURL );
+ aInetObj.insertName( rLib.aName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( !xSFI->isFolder( aLibDirPath ) )
+ {
+ xSFI->createFolder( aLibDirPath );
+ }
+ aInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aInetObj.setExtension( u"xlb" );
+ aLibInfoPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ else
+ {
+ createAppLibraryFolder( pLib, rLib.aName );
+ aLibInfoPath = pLib->maLibInfoFileURL;
+ }
+
+ try
+ {
+ if( xSFI->exists( aLibInfoPath ) )
+ {
+ xSFI->kill( aLibInfoPath );
+ }
+ xOut = xSFI->openFileWrite( aLibInfoPath );
+ }
+ catch(const Exception& )
+ {
+ if( bExport )
+ {
+ throw;
+ }
+ SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ }
+ if( !xOut.is() )
+ {
+ SAL_WARN("basic", "couldn't open output stream");
+ return;
+ }
+ xWriter->setOutputStream( xOut );
+ xmlscript::exportLibrary( xWriter, rLib );
+}
+
+
+bool SfxLibraryContainer::implLoadLibraryIndexFile( SfxLibrary* pLib,
+ ::xmlscript::LibDescriptor& rLib,
+ const uno::Reference< embed::XStorage >& xStorage,
+ const OUString& aIndexFileName )
+{
+ Reference< XParser > xParser = xml::sax::Parser::create(mxContext);
+
+ bool bStorage = false;
+ if( pLib )
+ {
+ bool bLink = pLib->mbLink;
+ bStorage = xStorage.is() && !bLink;
+ }
+
+ // Read info file
+ uno::Reference< io::XInputStream > xInput;
+ OUString aLibInfoPath;
+ if( bStorage )
+ {
+ aLibInfoPath = maInfoFileName + "-lb.xml";
+
+ try
+ {
+ uno::Reference< io::XStream > xInfoStream =
+ xStorage->openStreamElement( aLibInfoPath, embed::ElementModes::READ );
+ xInput = xInfoStream->getInputStream();
+ }
+ catch(const 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(const Exception& )
+ {
+ xInput.clear();
+ if( !GbMigrationSuppressErrors )
+ {
+ SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ }
+ }
+ if( !xInput.is() )
+ {
+ return false;
+ }
+
+ InputSource source;
+ source.aInputStream = xInput;
+ source.sSystemId = aLibInfoPath;
+
+ // start parsing
+ try
+ {
+ xParser->setDocumentHandler( ::xmlscript::importLibrary( rLib ) );
+ xParser->parseStream( source );
+ }
+ catch(const Exception& )
+ {
+ SAL_WARN("basic", "Parsing error");
+ SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aLibInfoPath );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ return false;
+ }
+
+ if( !pLib )
+ {
+ Reference< XNameContainer > xLib = createLibrary( rLib.aName );
+ pLib = static_cast< SfxLibrary* >( xLib.get() );
+ pLib->mbLoaded = false;
+ rLib.aStorageURL = aIndexFileName;
+ checkStorageURL( rLib.aStorageURL, pLib->maLibInfoFileURL, pLib->maStorageURL,
+ pLib->maUnexpandedStorageURL );
+
+ implImportLibDescriptor( pLib, rLib );
+ }
+
+ return true;
+}
+
+void SfxLibraryContainer::implImportLibDescriptor( SfxLibrary* pLib,
+ ::xmlscript::LibDescriptor const & rLib )
+{
+ if( pLib->mbInitialised )
+ return;
+
+ 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( false );
+ pLib->mbInitialised = true;
+}
+
+
+// Methods of new XLibraryStorage interface?
+void SfxLibraryContainer::storeLibraries_Impl( const uno::Reference< embed::XStorage >& i_rStorage,
+ bool bComplete )
+{
+ const Sequence< OUString > aNames = maNameContainer->getElementNames();
+ const 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--;
+ }
+ }
+ // Write to storage?
+ bool bStorage = i_rStorage.is();
+ uno::Reference< embed::XStorage > xSourceLibrariesStor;
+ uno::Reference< embed::XStorage > xTargetLibrariesStor;
+ OUString sTempTargetStorName;
+ const bool bInplaceStorage = bStorage && ( i_rStorage == mxStorage );
+
+ if( nLibsToSave == 0 )
+ {
+ if ( bInplaceStorage && mxStorage->hasByName(maLibrariesDir) )
+ {
+ mxStorage->removeElement(maLibrariesDir);
+ }
+ return;
+ }
+
+ if ( bStorage )
+ {
+ // Don't write if only empty standard lib exists
+ if ( ( nLibsToSave == 1 ) && ( aNames[0] == "Standard" ) )
+ {
+ Any aLibAny = maNameContainer->getByName( aNames[0] );
+ Reference< XNameAccess > xNameAccess;
+ aLibAny >>= xNameAccess;
+ if ( ! xNameAccess->hasElements() )
+ {
+ if ( bInplaceStorage && mxStorage->hasByName(maLibrariesDir) )
+ {
+ mxStorage->removeElement(maLibrariesDir);
+ }
+ return;
+ }
+ }
+
+ // create the empty target storage
+ try
+ {
+ OUString sTargetLibrariesStoreName;
+ if ( bInplaceStorage )
+ {
+ // create a temporary target storage
+ const OUStringBuffer aTempTargetNameBase = maLibrariesDir + "_temp_";
+ sal_Int32 index = 0;
+ do
+ {
+ 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_SET_THROW );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ return;
+ }
+
+ // open the source storage which might be used to copy yet-unmodified libraries
+ try
+ {
+ if ( mxStorage->hasByName( maLibrariesDir ) || bInplaceStorage )
+ {
+ xSourceLibrariesStor = mxStorage->openStorageElement( maLibrariesDir,
+ bInplaceStorage ? embed::ElementModes::READWRITE : embed::ElementModes::READ );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ return;
+ }
+ }
+
+ int iArray = 0;
+ pName = aNames.getConstArray();
+ ::xmlscript::LibDescriptor aLibDescriptorForExtensionLibs;
+ auto pLibArray = std::make_unique< ::xmlscript::LibDescriptorArray > ( nLibsToSave );
+ 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 )
+ {
+// Testing pImplLib->implIsModified() is not reliable,
+// IMHO the value of pImplLib->implIsModified() should
+// reflect whether the library ( in-memory ) model
+// is in sync with the library container's own storage. Currently
+// whenever the library model is written to *any* storage
+// pImplLib->implSetModified( sal_False ) is called
+// The way the code works, especially the way that sfx uses
+// temp storage when saving ( and later sets the root storage of the
+// library container ) and similar madness in dbaccess means some surgery
+// is required to make it possible to successfully use this optimisation
+// It would be possible to do the implSetModified() call below only
+// conditionally, but that would require an additional boolean to be
+// passed in via the XStorageBasedDocument::storeLibrariesToStorage()...
+// fdo#68983: If there's a password and the password is not known, only
+// copying the storage works!
+ // Can we simply copy the storage?
+ bool isCopyStorage = !mbOldInfoFormat && !mbOasis2OOoFormat
+ && !pImplLib->isLoadedStorable()
+ && xSourceLibrariesStor.is() /* null for user profile */;
+ if (isCopyStorage)
+ {
+ try
+ {
+ (void)xSourceLibrariesStor->isStorageElement(rLib.aName);
+ }
+ catch (container::NoSuchElementException const&)
+ {
+ isCopyStorage = false;
+ }
+ }
+ if (isCopyStorage)
+ {
+ try
+ {
+ xSourceLibrariesStor->copyElementTo( rLib.aName, xTargetLibrariesStor, rLib.aName );
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ // TODO: error handling?
+ }
+ }
+ else
+ {
+ uno::Reference< embed::XStorage > xLibraryStor;
+ if( bStorage )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ try
+ {
+#endif
+ xLibraryStor = xTargetLibrariesStor->openStorageElement(
+ rLib.aName,
+ embed::ElementModes::READWRITE );
+#if OSL_DEBUG_LEVEL > 0
+ }
+ catch(const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "basic",
+ "couldn't create sub storage for library \"" << rLib.aName << "\"");
+ throw;
+ }
+#endif
+ }
+
+ // 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(const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ // TODO: error handling
+ throw;
+ }
+ }
+ }
+ maModifiable.setModified( true );
+ pImplLib->implSetModified( 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.isEmpty() )
+ {
+ SAL_WARN_IF(
+ !xSourceLibrariesStor.is(), "basic",
+ ("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 "target 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< OUString > aRemoveNames( xSourceLibrariesStor->getElementNames() );
+ for ( auto const & removeName : aRemoveNames )
+ {
+ xSourceLibrariesStor->removeElement( removeName );
+ }
+
+ // copy
+ const Sequence< OUString > aCopyNames( xTargetLibrariesStor->getElementNames() );
+ for ( auto const & copyName : aCopyNames )
+ {
+ xTargetLibrariesStor->copyElementTo( copyName, xSourceLibrariesStor, copyName );
+ }
+ }
+
+ // close and remove temp target
+ xTargetLibrariesStor->dispose();
+ i_rStorage->removeElement( sTempTargetStorName );
+ xTargetLibrariesStor.clear();
+ sTempTargetStorName.clear();
+
+ // adjust target
+ xTargetLibrariesStor = xSourceLibrariesStor;
+ xSourceLibrariesStor.clear();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ throw;
+ }
+ }
+
+ if( !mbOldInfoFormat && !maModifiable.isModified() )
+ {
+ return;
+ }
+ maModifiable.setModified( false );
+ mbOldInfoFormat = false;
+
+ // Write library container info
+ // Create sax writer
+ Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
+
+ // Write info file
+ uno::Reference< io::XOutputStream > xOut;
+ uno::Reference< io::XStream > xInfoStream;
+ if( bStorage )
+ {
+ OUString aStreamName = maInfoFileName + "-lc.xml";
+
+ try
+ {
+ xInfoStream = xTargetLibrariesStor->openStreamElement( aStreamName, embed::ElementModes::READWRITE );
+ uno::Reference< beans::XPropertySet > xProps( xInfoStream, uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
+
+ // #87671 Allow encryption
+ xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::Any( true ) );
+
+ xOut = xInfoStream->getOutputStream();
+ }
+ catch(const uno::Exception& )
+ {
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ }
+ else
+ {
+ // Create Output stream
+ INetURLObject aLibInfoInetObj( o3tl::getToken(maLibraryPath, 1, ';') );
+ aLibInfoInetObj.insertName( maInfoFileName, false, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aLibInfoInetObj.setExtension( u"xlc" );
+ OUString aLibInfoPath( aLibInfoInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ try
+ {
+ if( mxSFI->exists( aLibInfoPath ) )
+ {
+ mxSFI->kill( aLibInfoPath );
+ }
+ xOut = mxSFI->openFileWrite( aLibInfoPath );
+ }
+ catch(const Exception& )
+ {
+ xOut.clear();
+ SfxErrorContext aEc( ERRCTX_SFX_SAVEDOC, aLibInfoPath );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+
+ }
+ if( !xOut.is() )
+ {
+ SAL_WARN("basic", "couldn't open output stream");
+ return;
+ }
+
+ xWriter->setOutputStream( xOut );
+
+ try
+ {
+ xmlscript::exportLibraryContainer( xWriter, pLibArray.get() );
+ if ( bStorage )
+ {
+ uno::Reference< embed::XTransactedObject > xTransact( xTargetLibrariesStor, uno::UNO_QUERY_THROW );
+ xTransact->commit();
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ SAL_WARN("basic", "Problem during storing of libraries!");
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+}
+
+
+// Methods XElementAccess
+Type SAL_CALL SfxLibraryContainer::getElementType()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return maNameContainer->getElementType();
+}
+
+sal_Bool SfxLibraryContainer::hasElements()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ bool bRet = maNameContainer->hasElements();
+ return bRet;
+}
+
+// Methods XNameAccess
+Any SfxLibraryContainer::getByName( const OUString& aName )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ Any aRetAny = maNameContainer->getByName( aName ) ;
+ return aRetAny;
+}
+
+Sequence< OUString > SfxLibraryContainer::getElementNames()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return maNameContainer->getElementNames();
+}
+
+sal_Bool SfxLibraryContainer::hasByName( const OUString& aName )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return maNameContainer->hasByName( aName ) ;
+}
+
+// Methods XLibraryContainer
+Reference< XNameContainer > SAL_CALL SfxLibraryContainer::createLibrary( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ rtl::Reference<SfxLibrary> pNewLib = implCreateLibrary( Name );
+ pNewLib->maLibElementFileExtension = maLibElementFileExtension;
+
+ createVariableURL( pNewLib->maUnexpandedStorageURL, Name, maInfoFileName, true );
+
+ Reference< XNameAccess > xNameAccess( pNewLib );
+ Any aElement;
+ aElement <<= xNameAccess;
+ maNameContainer->insertByName( Name, aElement );
+ maModifiable.setModified( true );
+ Reference< XNameContainer > xRet( xNameAccess, UNO_QUERY );
+ return xRet;
+}
+
+Reference< XNameAccess > SAL_CALL SfxLibraryContainer::createLibraryLink
+ ( const OUString& Name, const OUString& StorageURL, sal_Bool ReadOnly )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ // TODO: Check other reasons to force ReadOnly status
+ //if( !ReadOnly )
+ //{
+ //}
+
+ OUString aLibInfoFileURL;
+ OUString aLibDirURL;
+ OUString aUnexpandedStorageURL;
+ checkStorageURL( StorageURL, aLibInfoFileURL, aLibDirURL, aUnexpandedStorageURL );
+
+
+ rtl::Reference<SfxLibrary> pNewLib = implCreateLibraryLink( Name, aLibInfoFileURL, aLibDirURL, ReadOnly );
+ pNewLib->maLibElementFileExtension = maLibElementFileExtension;
+ pNewLib->maUnexpandedStorageURL = aUnexpandedStorageURL;
+ pNewLib->maOriginalStorageURL = StorageURL;
+
+ uno::Reference< embed::XStorage > xDummyStor;
+ ::xmlscript::LibDescriptor aLibDesc;
+ implLoadLibraryIndexFile( pNewLib.get(), aLibDesc, xDummyStor, OUString() );
+ implImportLibDescriptor( pNewLib.get(), aLibDesc );
+
+ Reference< XNameAccess > xRet( pNewLib );
+ Any aElement;
+ aElement <<= xRet;
+ maNameContainer->insertByName( Name, aElement );
+ maModifiable.setModified( true );
+
+ if( StorageURL.indexOf( "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE" ) != -1 )
+ {
+ pNewLib->mbExtension = true;
+ }
+ else if( StorageURL.indexOf( "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE" ) != -1
+ || StorageURL.indexOf( "vnd.sun.star.expand:$BUNDLED_EXTENSIONS" ) != -1 )
+ {
+ pNewLib->mbExtension = true;
+ pNewLib->mbReadOnly = true;
+ }
+
+ return xRet;
+}
+
+void SAL_CALL SfxLibraryContainer::removeLibrary( const OUString& Name )
+{
+ 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("readonly && !link", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ // Remove from container
+ maNameContainer->removeByName( Name );
+ maModifiable.setModified( true );
+
+ // Delete library files, but not for linked libraries
+ if( pImplLib->mbLink )
+ return;
+
+ 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 );
+ OUString aLibInfoPath = pImplLib->maLibInfoFileURL;
+ try
+ {
+ if( mxSFI->exists( aLibInfoPath ) )
+ {
+ mxSFI->kill( aLibInfoPath );
+ }
+ }
+ catch(const Exception& ) {}
+
+ // Delete folder if empty
+ INetURLObject aInetObj( o3tl::getToken(maLibraryPath, 1, ';') );
+ aInetObj.insertName( Name, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ OUString aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ try
+ {
+ if( mxSFI->isFolder( aLibDirPath ) )
+ {
+ Sequence< OUString > aContentSeq = mxSFI->getFolderContents( aLibDirPath, true );
+ sal_Int32 nCount = aContentSeq.getLength();
+ if( !nCount )
+ {
+ mxSFI->kill( aLibDirPath );
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ }
+}
+
+sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLoaded( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bRet = pImplLib->mbLoaded;
+ return bRet;
+}
+
+
+void SAL_CALL SfxLibraryContainer::loadLibrary( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ Any aLibAny = maNameContainer->getByName( Name ) ;
+ Reference< XNameAccess > xNameAccess;
+ aLibAny >>= xNameAccess;
+ SfxLibrary* pImplLib = static_cast< SfxLibrary* >( xNameAccess.get() );
+
+ bool bLoaded = pImplLib->mbLoaded;
+ pImplLib->mbLoaded = true;
+ if( bLoaded || !xNameAccess->hasElements() )
+ return;
+
+ if( pImplLib->mbPasswordProtected )
+ {
+ implLoadPasswordLibrary( pImplLib, Name );
+ return;
+ }
+
+ bool bLink = pImplLib->mbLink;
+ bool bStorage = mxStorage.is() && !bLink;
+
+ uno::Reference< embed::XStorage > xLibrariesStor;
+ uno::Reference< embed::XStorage > xLibraryStor;
+ if( bStorage )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ try
+ {
+#endif
+ xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
+ SAL_WARN_IF(
+ !xLibrariesStor.is(), "basic",
+ ("The method must either throw exception or return a"
+ " storage!"));
+ if ( !xLibrariesStor.is() )
+ {
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+ }
+
+ xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
+ SAL_WARN_IF(
+ !xLibraryStor.is(), "basic",
+ ("The method must either throw exception or return a"
+ " storage!"));
+ if ( !xLibrariesStor.is() )
+ {
+ throw uno::RuntimeException("null returned from openStorageElement",static_cast< cppu::OWeakObject * >(this));
+ }
+#if OSL_DEBUG_LEVEL > 0
+ }
+ catch(const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "basic",
+ "couldn't open sub storage for library \"" << Name << "\"");
+ throw;
+ }
+#endif
+ }
+
+ 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 + ".xml";
+
+ try
+ {
+ xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
+ }
+ catch(const uno::Exception& )
+ {}
+
+ if( !xElementStream.is() )
+ {
+ // Check for EA2 document version with wrong extensions
+ aFile = aElementName + "." + maLibElementFileExtension;
+ try
+ {
+ xElementStream = xLibraryStor->openStreamElement( aFile, embed::ElementModes::READ );
+ }
+ catch(const uno::Exception& )
+ {}
+ }
+
+ if ( xElementStream.is() )
+ {
+ xInStream = xElementStream->getInputStream();
+ }
+ if ( !xInStream.is() )
+ {
+ SAL_WARN(
+ "basic",
+ "couldn't open library element stream - attempted to"
+ " open library \"" << Name << '"');
+ throw RuntimeException("couldn't open library element stream", *this);
+ }
+ }
+ else
+ {
+ OUString aLibDirPath = pImplLib->maStorageURL;
+ INetURLObject aElementInetObj( aLibDirPath );
+ aElementInetObj.insertName( aElementName, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( maLibElementFileExtension );
+ aFile = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+
+ 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->insertNoCheck(aElementName, aAny);
+ }
+ }
+ pImplLib->implSetModified( false );
+}
+
+// Methods XLibraryContainer2
+sal_Bool SAL_CALL SfxLibraryContainer::isLibraryLink( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bRet = pImplLib->mbLink;
+ return bRet;
+}
+
+OUString SAL_CALL SfxLibraryContainer::getLibraryLinkURL( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bLink = pImplLib->mbLink;
+ if( !bLink )
+ {
+ throw IllegalArgumentException("!link", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ OUString aRetStr = pImplLib->maLibInfoFileURL;
+ return aRetStr;
+}
+
+sal_Bool SAL_CALL SfxLibraryContainer::isLibraryReadOnly( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bRet = pImplLib->mbReadOnly || (pImplLib->mbLink && pImplLib->mbReadOnlyLink);
+ return bRet;
+}
+
+void SAL_CALL SfxLibraryContainer::setLibraryReadOnly( const OUString& Name, sal_Bool bReadOnly )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ if( pImplLib->mbLink )
+ {
+ if( pImplLib->mbReadOnlyLink != bool(bReadOnly) )
+ {
+ pImplLib->mbReadOnlyLink = bReadOnly;
+ pImplLib->implSetModified( true );
+ maModifiable.setModified( true );
+ }
+ }
+ else
+ {
+ if( pImplLib->mbReadOnly != bool(bReadOnly) )
+ {
+ pImplLib->mbReadOnly = bReadOnly;
+ pImplLib->implSetModified( true );
+ }
+ }
+}
+
+void SAL_CALL SfxLibraryContainer::renameLibrary( const OUString& Name, const OUString& NewName )
+{
+ 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( true );
+
+ // Rename library folder, but not for linked libraries
+ bool bMovedSuccessful = true;
+
+ // Rename files
+ bool bStorage = mxStorage.is();
+ if( !bStorage && !pImplLib->mbLink )
+ {
+ bMovedSuccessful = false;
+
+ OUString aLibDirPath = pImplLib->maStorageURL;
+
+ INetURLObject aDestInetObj( o3tl::getToken(maLibraryPath, 1, ';'));
+ aDestInetObj.insertName( NewName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ OUString aDestDirPath = aDestInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ // 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(const 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, false,
+ INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( maLibElementFileExtension );
+ OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ INetURLObject aElementDestInetObj( aDestDirPath );
+ aElementDestInetObj.insertName( aElementName, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aElementDestInetObj.setExtension( maLibElementFileExtension );
+ OUString aDestElementPath( aElementDestInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ try
+ {
+ if( mxSFI->exists( aDestElementPath ) )
+ {
+ mxSFI->kill( aDestElementPath );
+ }
+ mxSFI->move( aElementPath, aDestElementPath );
+ }
+ catch(const 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( true );
+ }
+ }
+ catch(const Exception& )
+ {
+ // Restore old library
+ maNameContainer->insertByName( Name, aLibAny ) ;
+ }
+ }
+
+ if( bStorage && !pImplLib->mbLink )
+ {
+ pImplLib->implSetModified( true );
+ }
+ if( bMovedSuccessful )
+ {
+ maNameContainer->insertByName( NewName, aLibAny ) ;
+ }
+}
+
+
+// Methods XInitialization
+void SAL_CALL SfxLibraryContainer::initialize( const Sequence< Any >& _rArguments )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ sal_Int32 nArgCount = _rArguments.getLength();
+ if ( nArgCount != 1 )
+ throw IllegalArgumentException("too many args", static_cast<cppu::OWeakObject*>(this), -1);
+
+ OUString sInitialDocumentURL;
+ Reference< XStorageBasedDocument > xDocument;
+ if ( _rArguments[0] >>= sInitialDocumentURL )
+ {
+ init( sInitialDocumentURL, nullptr );
+ return;
+ }
+
+ if ( _rArguments[0] >>= xDocument )
+ {
+ initializeFromDocument( xDocument );
+ return;
+ }
+ throw IllegalArgumentException("arg1 unknown type", static_cast<cppu::OWeakObject*>(this), 1);
+
+}
+
+void 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("com.sun.star.document.OfficeDocument"))
+ {
+ xDocStorage.set( _rxDocument->getDocumentStorage(), UNO_SET_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("no doc storage", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ init( OUString(), xDocStorage );
+}
+
+// OEventListenerAdapter
+void SfxLibraryContainer::_disposing( const EventObject& _rSource )
+{
+#if OSL_DEBUG_LEVEL > 0
+ Reference< XModel > xDocument( mxOwnerDocument.get(), UNO_QUERY );
+ SAL_WARN_IF(
+ xDocument != _rSource.Source || !xDocument.is(), "basic",
+ "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 );
+ maVBAScriptListeners.disposeAndClear( aEvent );
+ stopAllComponentListening();
+ mxOwnerDocument.clear();
+}
+
+// Methods XLibraryContainerPassword
+sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordProtected( const OUString& )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL SfxLibraryContainer::isLibraryPasswordVerified( const OUString& )
+{
+ throw IllegalArgumentException();
+}
+
+sal_Bool SAL_CALL SfxLibraryContainer::verifyLibraryPassword( const OUString&, const OUString& )
+{
+ throw IllegalArgumentException();
+}
+
+void SAL_CALL SfxLibraryContainer::changeLibraryPassword(const OUString&, const OUString&, const OUString& )
+{
+ throw IllegalArgumentException();
+}
+
+// Methods XContainer
+void SAL_CALL SfxLibraryContainer::addContainerListener( const Reference< XContainerListener >& xListener )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
+ maNameContainer->addContainerListener( xListener );
+}
+
+void SAL_CALL SfxLibraryContainer::removeContainerListener( const Reference< XContainerListener >& xListener )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ maNameContainer->removeContainerListener( xListener );
+}
+
+// Methods XLibraryContainerExport
+void SAL_CALL SfxLibraryContainer::exportLibrary( const OUString& Name, const OUString& URL,
+ const Reference< XInteractionHandler >& Handler )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+
+ Reference< XSimpleFileAccess3 > xToUseSFI;
+ if( Handler.is() )
+ {
+ xToUseSFI = ucb::SimpleFileAccess::create( mxContext );
+ xToUseSFI->setInteractionHandler( Handler );
+ }
+
+ // Maybe lib is not loaded?!
+ loadLibrary( Name );
+
+ uno::Reference< css::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 )
+{
+ if (url.startsWithIgnoreAsciiCase( "vnd.sun.star.expand:" ))
+ {
+ return comphelper::getExpandedUri(mxContext, url);
+ }
+ else if( mxStringSubstitution.is() )
+ {
+ OUString ret( mxStringSubstitution->substituteVariables( url, false ) );
+ return ret;
+ }
+ else
+ {
+ return url;
+ }
+}
+
+//XLibraryContainer3
+OUString SAL_CALL SfxLibraryContainer::getOriginalLibraryLinkURL( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bLink = pImplLib->mbLink;
+ if( !bLink )
+ {
+ throw IllegalArgumentException("!link", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ OUString aRetStr = pImplLib->maOriginalStorageURL;
+ return aRetStr;
+}
+
+
+// XVBACompatibility
+sal_Bool SAL_CALL SfxLibraryContainer::getVBACompatibilityMode()
+{
+ return mbVBACompat;
+}
+
+void SAL_CALL SfxLibraryContainer::setVBACompatibilityMode( sal_Bool _vbacompatmodeon )
+{
+ /* The member variable mbVBACompat must be set first, the following call
+ to getBasicManager() may call getVBACompatibilityMode() which returns
+ this value. */
+ mbVBACompat = _vbacompatmodeon;
+ BasicManager* pBasMgr = getBasicManager();
+ if( !pBasMgr )
+ return;
+
+ // get the standard library
+ OUString aLibName = pBasMgr->GetName();
+ if ( aLibName.isEmpty())
+ {
+ aLibName = "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("ooo.vba.VBAGlobals");
+ }
+ catch(const Exception& )
+ {
+ }
+}
+
+void SAL_CALL SfxLibraryContainer::setProjectName( const OUString& _projectname )
+{
+ msProjectName = _projectname;
+ BasicManager* pBasMgr = getBasicManager();
+ // Temporary HACK
+ // Some parts of the VBA handling ( e.g. in core basic )
+ // code expect the name of the VBA project to be set as the name of
+ // the basic manager. Provide fail back here.
+ if( pBasMgr )
+ {
+ pBasMgr->SetName( msProjectName );
+ }
+}
+
+sal_Int32 SAL_CALL SfxLibraryContainer::getRunningVBAScripts()
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ return mnRunningVBAScripts;
+}
+
+void SAL_CALL SfxLibraryContainer::addVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener )
+{
+ maVBAScriptListeners.addInterface( rxListener );
+}
+
+void SAL_CALL SfxLibraryContainer::removeVBAScriptListener( const Reference< vba::XVBAScriptListener >& rxListener )
+{
+ maVBAScriptListeners.removeInterface( rxListener );
+}
+
+void SAL_CALL SfxLibraryContainer::broadcastVBAScriptEvent( sal_Int32 nIdentifier, const OUString& rModuleName )
+{
+ // 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
+ vba::VBAScriptEvent aEvent( Reference<XInterface>(xModel, UNO_QUERY), nIdentifier, rModuleName );
+ maVBAScriptListeners.notifyEach( &css::script::vba::XVBAScriptListener::notifyVBAScriptEvent, aEvent );
+}
+
+// Methods XPropertySet
+css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL SfxLibraryContainer::getPropertySetInfo()
+{
+ return uno::Reference<beans::XPropertySetInfo>();
+}
+
+void SAL_CALL SfxLibraryContainer::setPropertyValue(const OUString& aPropertyName,
+ const uno::Any& aValue)
+{
+ if (aPropertyName != sVBATextEncodingPropName)
+ throw UnknownPropertyException(aPropertyName, static_cast<uno::XWeak*>(this));
+ aValue >>= meVBATextEncoding;
+}
+
+css::uno::Any SAL_CALL SfxLibraryContainer::getPropertyValue(const OUString& aPropertyName)
+{
+ if (aPropertyName == sVBATextEncodingPropName)
+ return uno::Any(meVBATextEncoding);
+ throw UnknownPropertyException(aPropertyName, static_cast<uno::XWeak*>(this));
+}
+
+void SAL_CALL SfxLibraryContainer::addPropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener>& /* xListener */)
+{
+ throw NoSupportException();
+}
+
+void SAL_CALL SfxLibraryContainer::removePropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener>& /* aListener */)
+{
+ throw NoSupportException();
+}
+
+void SAL_CALL SfxLibraryContainer::addVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener>& /* aListener */)
+{
+ throw NoSupportException();
+}
+
+void SAL_CALL SfxLibraryContainer::removeVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener>& /* aListener */)
+{
+ throw NoSupportException();
+}
+
+// Methods XServiceInfo
+sal_Bool SAL_CALL SfxLibraryContainer::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+// Implementation class SfxLibrary
+
+// Ctor
+SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
+ const Reference< XSimpleFileAccess3 >& xSFI )
+ : OComponentHelper( m_aMutex )
+ , mxSFI( xSFI )
+ , mrModifiable( _rModifiable )
+ , maNameContainer( new NameContainer(aType) )
+ , mbLoaded( true )
+ , mbIsModified( true )
+ , mbInitialised( false )
+ , mbLink( false )
+ , mbReadOnly( false )
+ , mbReadOnlyLink( false )
+ , mbPreload( false )
+ , mbPasswordProtected( false )
+ , mbPasswordVerified( false )
+ , mbDoc50Password( false )
+ , mbSharedIndexFile( false )
+ , mbExtension( false )
+{
+}
+
+SfxLibrary::SfxLibrary( ModifiableHelper& _rModifiable, const Type& aType,
+ const Reference< XSimpleFileAccess3 >& xSFI,
+ OUString aLibInfoFileURL, OUString aStorageURL, bool ReadOnly )
+ : OComponentHelper( m_aMutex )
+ , mxSFI( xSFI )
+ , mrModifiable( _rModifiable )
+ , maNameContainer( new NameContainer(aType) )
+ , mbLoaded( false )
+ , mbIsModified( true )
+ , mbInitialised( false )
+ , maLibInfoFileURL(std::move( aLibInfoFileURL ))
+ , maStorageURL(std::move( aStorageURL ))
+ , mbLink( true )
+ , mbReadOnly( false )
+ , mbReadOnlyLink( ReadOnly )
+ , mbPreload( false )
+ , mbPasswordProtected( false )
+ , mbPasswordVerified( false )
+ , mbDoc50Password( false )
+ , mbSharedIndexFile( false )
+ , mbExtension( false )
+{
+}
+
+bool SfxLibrary::isLoadedStorable()
+{
+ return mbLoaded && (!mbPasswordProtected || mbPasswordVerified);
+}
+
+void SfxLibrary::implSetModified( bool _bIsModified )
+{
+ if ( mbIsModified == _bIsModified )
+ {
+ return;
+ }
+ mbIsModified = _bIsModified;
+ if ( mbIsModified )
+ {
+ mrModifiable.setModified( true );
+ }
+}
+
+// Methods XInterface
+Any SAL_CALL SfxLibrary::queryInterface( const Type& rType )
+{
+ Any aRet =
+ ::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()
+{
+ return maNameContainer->getElementType();
+}
+
+sal_Bool SfxLibrary::hasElements()
+{
+ bool bRet = maNameContainer->hasElements();
+ return bRet;
+}
+
+// Methods XNameAccess
+Any SfxLibrary::getByName( const OUString& aName )
+{
+ impl_checkLoaded();
+
+ Any aRetAny = maNameContainer->getByName( aName ) ;
+ return aRetAny;
+}
+
+Sequence< OUString > SfxLibrary::getElementNames()
+{
+ return maNameContainer->getElementNames();
+}
+
+sal_Bool SfxLibrary::hasByName( const OUString& aName )
+{
+ bool bRet = maNameContainer->hasByName( aName );
+ return bRet;
+}
+
+void SfxLibrary::impl_checkReadOnly()
+{
+ if( mbReadOnly || (mbLink && mbReadOnlyLink) )
+ {
+ throw IllegalArgumentException(
+ "Library is readonly.",
+ // TODO: resource
+ *this, 0
+ );
+ }
+}
+
+void SfxLibrary::impl_checkLoaded()
+{
+ if ( !mbLoaded )
+ {
+ throw WrappedTargetException(
+ OUString(),
+ *this,
+ Any( LibraryNotLoadedException(
+ OUString(),
+ *this
+ ) )
+ );
+ }
+}
+
+// Methods XNameReplace
+void SfxLibrary::replaceByName( const OUString& aName, const Any& aElement )
+{
+ impl_checkReadOnly();
+ impl_checkLoaded();
+
+ SAL_WARN_IF(
+ !isLibraryElementValid(aElement), "basic",
+ "SfxLibrary::replaceByName: replacing element is invalid!");
+
+ maNameContainer->replaceByName( aName, aElement );
+ implSetModified( true );
+}
+
+
+// Methods XNameContainer
+void SfxLibrary::insertByName( const OUString& aName, const Any& aElement )
+{
+ impl_checkReadOnly();
+ impl_checkLoaded();
+
+ SAL_WARN_IF(
+ !isLibraryElementValid(aElement), "basic",
+ "SfxLibrary::insertByName: to-be-inserted element is invalid!");
+
+ maNameContainer->insertByName( aName, aElement );
+ implSetModified( true );
+}
+
+void SfxLibrary::impl_removeWithoutChecks( const OUString& _rElementName )
+{
+ maNameContainer->removeByName( _rElementName );
+ implSetModified( true );
+
+ // Remove element file
+ if( maStorageURL.isEmpty() )
+ return;
+
+ INetURLObject aElementInetObj( maStorageURL );
+ aElementInetObj.insertName( _rElementName, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( maLibElementFileExtension );
+ OUString aFile = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ try
+ {
+ if( mxSFI->exists( aFile ) )
+ {
+ mxSFI->kill( aFile );
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("basic");
+ }
+}
+
+void SfxLibrary::removeByName( const OUString& Name )
+{
+ impl_checkReadOnly();
+ impl_checkLoaded();
+ impl_removeWithoutChecks( Name );
+}
+
+// XTypeProvider
+Sequence< Type > SfxLibrary::getTypes()
+{
+ static OTypeCollection ourTypes_NameContainer(
+ cppu::UnoType<XNameContainer>::get(),
+ cppu::UnoType<XContainer>::get(),
+ cppu::UnoType<XChangesNotifier>::get(),
+ OComponentHelper::getTypes() );
+
+ return ourTypes_NameContainer.getTypes();
+}
+
+
+Sequence< sal_Int8 > SfxLibrary::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// Methods XContainer
+void SAL_CALL SfxLibrary::addContainerListener( const Reference< XContainerListener >& xListener )
+{
+ maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
+ maNameContainer->addContainerListener( xListener );
+}
+
+void SAL_CALL SfxLibrary::removeContainerListener( const Reference< XContainerListener >& xListener )
+{
+ maNameContainer->removeContainerListener( xListener );
+}
+
+// Methods XChangesNotifier
+void SAL_CALL SfxLibrary::addChangesListener( const Reference< XChangesListener >& xListener )
+{
+ maNameContainer->setEventSource( static_cast< XInterface* >( static_cast<OWeakObject*>(this) ) );
+ maNameContainer->addChangesListener( xListener );
+}
+
+void SAL_CALL SfxLibrary::removeChangesListener( const Reference< XChangesListener >& xListener )
+{
+ maNameContainer->removeChangesListener( xListener );
+}
+
+
+// Implementation class ScriptExtensionIterator
+
+constexpr OUStringLiteral sBasicLibMediaType = u"application/vnd.sun.star.basic-library";
+constexpr OUStringLiteral sDialogLibMediaType = u"application/vnd.sun.star.dialog-library";
+
+ScriptExtensionIterator::ScriptExtensionIterator()
+ : m_xContext( comphelper::getProcessComponentContext() )
+ , m_eState( USER_EXTENSIONS )
+ , m_bUserPackagesLoaded( false )
+ , m_bSharedPackagesLoaded( false )
+ , m_bBundledPackagesLoaded( false )
+ , m_iUserPackage( 0 )
+ , m_iSharedPackage( 0 )
+ , m_iBundledPackage( 0 )
+ , m_pScriptSubPackageIterator( nullptr )
+{}
+
+OUString ScriptExtensionIterator::nextBasicOrDialogLibrary( bool& rbPureDialogLib )
+{
+ OUString aRetLib;
+
+ while( aRetLib.isEmpty() && 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:
+ SAL_WARN(
+ "basic",
+ ("ScriptExtensionIterator::nextBasicOrDialogLibrary():"
+ " Invalid case END_REACHED"));
+ break;
+ }
+ }
+
+ return aRetLib;
+}
+
+ScriptSubPackageIterator::ScriptSubPackageIterator( Reference< deployment::XPackage > const & xMainPackage )
+ : m_xMainPackage( xMainPackage )
+ , m_bIsValid( false )
+ , m_bIsBundle( false )
+ , m_nSubPkgCount( 0 )
+ , m_iNextSubPkg( 0 )
+{
+ 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 >& rPackage,
+ bool& rbPureDialogLib )
+{
+ Reference< deployment::XPackage > xScriptPackage;
+
+ if( rPackage.is() )
+ {
+ const Reference< deployment::XPackageTypeInfo > xPackageTypeInfo = rPackage->getPackageType();
+ OUString aMediaType = xPackageTypeInfo->getMediaType();
+ if ( aMediaType == sBasicLibMediaType )
+ {
+ xScriptPackage = rPackage;
+ }
+ else if ( aMediaType == sDialogLibMediaType )
+ {
+ rbPureDialogLib = true;
+ xScriptPackage = rPackage;
+ }
+ }
+
+ 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("user",
+ Reference< task::XAbortChannel >(),
+ Reference< ucb::XCommandEnvironment >() );
+ }
+ catch(const css::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 == nullptr )
+ {
+ const Reference< deployment::XPackage >* pUserPackages = m_aUserPackagesSeq.getConstArray();
+ Reference< deployment::XPackage > xPackage = pUserPackages[ m_iUserPackage ];
+ SAL_WARN_IF(
+ !xPackage.is(), "basic",
+ ("ScriptExtensionIterator::implGetNextUserScriptPackage():"
+ " Invalid package"));
+ m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
+ }
+
+ xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
+ if( !xScriptPackage.is() )
+ {
+ delete m_pScriptSubPackageIterator;
+ m_pScriptSubPackageIterator = nullptr;
+ 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("shared",
+ Reference< task::XAbortChannel >(),
+ Reference< ucb::XCommandEnvironment >() );
+ }
+ catch(const css::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 == nullptr )
+ {
+ const Reference< deployment::XPackage >* pSharedPackages = m_aSharedPackagesSeq.getConstArray();
+ Reference< deployment::XPackage > xPackage = pSharedPackages[ m_iSharedPackage ];
+ SAL_WARN_IF(
+ !xPackage.is(), "basic",
+ ("ScriptExtensionIterator::implGetNextSharedScriptPackage():"
+ " Invalid package"));
+ m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
+ }
+
+ xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
+ if( !xScriptPackage.is() )
+ {
+ delete m_pScriptSubPackageIterator;
+ m_pScriptSubPackageIterator = nullptr;
+ 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("bundled",
+ Reference< task::XAbortChannel >(),
+ Reference< ucb::XCommandEnvironment >() );
+ }
+ catch(const css::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 == nullptr )
+ {
+ const Reference< deployment::XPackage >* pBundledPackages = m_aBundledPackagesSeq.getConstArray();
+ Reference< deployment::XPackage > xPackage = pBundledPackages[ m_iBundledPackage ];
+ SAL_WARN_IF(
+ !xPackage.is(), "basic",
+ ("ScriptExtensionIterator::implGetNextBundledScriptPackage():"
+ " Invalid package"));
+ m_pScriptSubPackageIterator = new ScriptSubPackageIterator( xPackage );
+ }
+
+ xScriptPackage = m_pScriptSubPackageIterator->getNextScriptSubPackage( rbPureDialogLib );
+ if( !xScriptPackage.is() )
+ {
+ delete m_pScriptSubPackageIterator;
+ m_pScriptSubPackageIterator = nullptr;
+ m_iBundledPackage++;
+ }
+ }
+
+ return xScriptPackage;
+}
+
+} // namespace basic
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/basic/source/uno/scriptcont.cxx b/basic/source/uno/scriptcont.cxx
new file mode 100644
index 000000000..52413b759
--- /dev/null
+++ b/basic/source/uno/scriptcont.cxx
@@ -0,0 +1,1243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <scriptcont.hxx>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/task/ErrorCodeIOException.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/storagehelper.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <sal/log.hxx>
+#include <sot/storage.hxx>
+
+// For password functionality
+#include <tools/urlobj.hxx>
+
+
+#include <svtools/sfxecode.hxx>
+#include <svtools/ehdl.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/modsizeexceeded.hxx>
+#include <xmlscript/xmlmod_imexp.hxx>
+#include <com/sun/star/util/VetoException.hpp>
+#include <memory>
+
+namespace basic
+{
+
+using namespace com::sun::star::document;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::script;
+using namespace com::sun::star::xml::sax;
+using namespace com::sun::star;
+using namespace cppu;
+using namespace osl;
+
+
+// Implementation class SfxScriptLibraryContainer
+
+OUString SfxScriptLibraryContainer::getInfoFileName() const
+{
+ static constexpr OUStringLiteral script = u"script";
+ return script;
+}
+OUString SfxScriptLibraryContainer::getOldInfoFileName() const
+{
+ static constexpr OUStringLiteral script = u"script";
+ return script;
+}
+OUString SfxScriptLibraryContainer::getLibElementFileExtension() const
+{
+ static constexpr OUStringLiteral xba = u"xba";
+ return xba;
+}
+OUString SfxScriptLibraryContainer::getLibrariesDir() const
+{
+ static constexpr OUStringLiteral sBasic = u"Basic";
+ return sBasic;
+}
+
+// OldBasicPassword interface
+void SfxScriptLibraryContainer::setLibraryPassword( const OUString& rLibraryName, const OUString& rPassword )
+{
+ try
+ {
+ SfxLibrary* pImplLib = getImplLib( rLibraryName );
+ if( !rPassword.isEmpty() )
+ {
+ pImplLib->mbDoc50Password = true;
+ pImplLib->mbPasswordProtected = true;
+ pImplLib->maPassword = rPassword;
+ SfxScriptLibrary *const pSL(dynamic_cast<SfxScriptLibrary *>(pImplLib));
+ if (pSL && pSL->mbLoaded)
+ {
+ pSL->mbLoadedSource = true; // must store source code now!
+ }
+ }
+ }
+ catch(const NoSuchElementException& ) {}
+}
+
+// Ctor for service
+SfxScriptLibraryContainer::SfxScriptLibraryContainer()
+{
+ // all initialisation has to be done
+ // by calling XInitialization::initialize
+}
+
+SfxScriptLibraryContainer::SfxScriptLibraryContainer( const uno::Reference< embed::XStorage >& xStorage )
+{
+ init( OUString(), xStorage );
+}
+
+// Methods to get library instances of the correct type
+rtl::Reference<SfxLibrary> SfxScriptLibraryContainer::implCreateLibrary( const OUString& )
+{
+ return new SfxScriptLibrary( maModifiable, mxSFI );
+}
+
+rtl::Reference<SfxLibrary> SfxScriptLibraryContainer::implCreateLibraryLink( const OUString&,
+ const OUString& aLibInfoFileURL,
+ const OUString& StorageURL,
+ bool ReadOnly )
+{
+ return new SfxScriptLibrary( maModifiable, mxSFI,
+ aLibInfoFileURL, StorageURL, ReadOnly );
+}
+
+Any SfxScriptLibraryContainer::createEmptyLibraryElement()
+{
+ Any aRetAny;
+ aRetAny <<= OUString();
+ return aRetAny;
+}
+
+bool SfxScriptLibraryContainer::isLibraryElementValid(const Any& rElement) const
+{
+ return SfxScriptLibrary::containsValidModule(rElement);
+}
+
+void SfxScriptLibraryContainer::writeLibraryElement( const Reference < XNameContainer >& xLib,
+ const OUString& aElementName,
+ const Reference< XOutputStream >& xOutput)
+{
+ // Create sax writer
+ Reference< XWriter > xWriter = xml::sax::Writer::create(mxContext);
+
+ Reference< XTruncate > xTruncate( xOutput, UNO_QUERY );
+ OSL_ENSURE( xTruncate.is(), "Currently only the streams that can be truncated are expected!" );
+ if ( xTruncate.is() )
+ {
+ xTruncate->truncate();
+ }
+ xWriter->setOutputStream( xOutput );
+
+ xmlscript::ModuleDescriptor aMod;
+ aMod.aName = aElementName;
+ aMod.aLanguage = "StarBasic";
+ Any aElement = xLib->getByName( aElementName );
+ aElement >>= aMod.aCode;
+
+ Reference< script::vba::XVBAModuleInfo > xModInfo( xLib, UNO_QUERY );
+ if( xModInfo.is() && xModInfo->hasModuleInfo( aElementName ) )
+ {
+ script::ModuleInfo aModInfo = xModInfo->getModuleInfo( aElementName );
+ switch( aModInfo.ModuleType )
+ {
+ case ModuleType::NORMAL:
+ aMod.aModuleType = "normal";
+ break;
+ case ModuleType::CLASS:
+ aMod.aModuleType ="class";
+ break;
+ case ModuleType::FORM:
+ aMod.aModuleType = "form";
+ break;
+ case ModuleType::DOCUMENT:
+ aMod.aModuleType = "document";
+ break;
+ case ModuleType::UNKNOWN:
+ // nothing
+ break;
+ }
+ }
+
+ xmlscript::exportScriptModule( xWriter, aMod );
+}
+
+
+Any SfxScriptLibraryContainer::importLibraryElement
+ ( const Reference < XNameContainer >& xLib,
+ const OUString& aElementName, const OUString& aFile,
+ const uno::Reference< io::XInputStream >& xInStream )
+{
+ Any aRetAny;
+
+ Reference< XParser > xParser = xml::sax::Parser::create( mxContext );
+
+ // Read from storage?
+ bool bStorage = xInStream.is();
+ Reference< XInputStream > xInput;
+
+ if( bStorage )
+ {
+ xInput = xInStream;
+ }
+ else
+ {
+ try
+ {
+ xInput = mxSFI->openFileRead( aFile );
+ }
+ catch(const Exception& )
+ //catch( Exception& e )
+ {
+ // TODO:
+ //throw WrappedTargetException( e );
+ }
+ }
+
+ if( !xInput.is() )
+ return aRetAny;
+
+ InputSource source;
+ source.aInputStream = xInput;
+ source.sSystemId = aFile;
+
+ // start parsing
+ xmlscript::ModuleDescriptor aMod;
+
+ try
+ {
+ xParser->setDocumentHandler( ::xmlscript::importScriptModule( aMod ) );
+ xParser->parseStream( source );
+ }
+ catch(const Exception& )
+ {
+ SfxErrorContext aEc( ERRCTX_SFX_LOADBASIC, aFile );
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+
+ aRetAny <<= aMod.aCode;
+
+ // TODO: Check language
+ // aMod.aLanguage
+ // aMod.aName ignored
+ if( !aMod.aModuleType.isEmpty() )
+ {
+ /* 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( getVBACompatibilityMode() ) try
+ {
+ Reference< frame::XModel > xModel( mxOwnerDocument ); // weak-ref -> ref
+ Reference< XMultiServiceFactory > xFactory( xModel, UNO_QUERY_THROW );
+ xFactory->createInstance("ooo.vba.VBAGlobals");
+ }
+ catch(const Exception& )
+ {
+ }
+
+ script::ModuleInfo aModInfo;
+ aModInfo.ModuleType = ModuleType::UNKNOWN;
+ if( aMod.aModuleType == "normal" )
+ {
+ aModInfo.ModuleType = ModuleType::NORMAL;
+ }
+ else if( aMod.aModuleType == "class" )
+ {
+ aModInfo.ModuleType = ModuleType::CLASS;
+ }
+ else if( aMod.aModuleType == "form" )
+ {
+ aModInfo.ModuleType = ModuleType::FORM;
+ aModInfo.ModuleObject = mxOwnerDocument;
+ }
+ else if( aMod.aModuleType == "document" )
+ {
+ aModInfo.ModuleType = ModuleType::DOCUMENT;
+
+ // #163691# use the same codename access instance for all document modules
+ if( !mxCodeNameAccess.is() ) try
+ {
+ Reference<frame::XModel > xModel( mxOwnerDocument );
+ Reference< XMultiServiceFactory> xSF( xModel, UNO_QUERY_THROW );
+ mxCodeNameAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), UNO_QUERY );
+ }
+ catch(const Exception& ) {}
+
+ if( mxCodeNameAccess.is() )
+ {
+ try
+ {
+ aModInfo.ModuleObject.set( mxCodeNameAccess->getByName( aElementName), uno::UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ SAL_WARN("basic", "Failed to get document object for " << aElementName );
+ }
+ }
+ }
+
+ Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY );
+ if( xVBAModuleInfo.is() )
+ {
+ if( xVBAModuleInfo->hasModuleInfo( aElementName ) )
+ {
+ xVBAModuleInfo->removeModuleInfo( aElementName );
+ }
+ xVBAModuleInfo->insertModuleInfo( aElementName, aModInfo );
+ }
+ }
+
+ return aRetAny;
+}
+
+rtl::Reference<SfxLibraryContainer> SfxScriptLibraryContainer::createInstanceImpl()
+{
+ return new SfxScriptLibraryContainer();
+}
+
+void SfxScriptLibraryContainer::importFromOldStorage( const OUString& aFile )
+{
+ // TODO: move loading from old storage to binary filters?
+ auto xStorage = tools::make_ref<SotStorage>( false, aFile );
+ if( xStorage->GetError() == ERRCODE_NONE )
+ {
+ auto pBasicManager = std::make_unique<BasicManager> ( *xStorage, aFile );
+
+ // Set info
+ LibraryContainerInfo aInfo( this, nullptr, static_cast< OldBasicPassword* >( this ) );
+ pBasicManager->SetLibraryContainerInfo( aInfo );
+ }
+}
+
+
+// Storing with password encryption
+
+// Methods XLibraryContainerPassword
+sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordProtected( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ bool bRet = pImplLib->mbPasswordProtected;
+ return bRet;
+}
+
+sal_Bool SAL_CALL SfxScriptLibraryContainer::isLibraryPasswordVerified( const OUString& Name )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ if( !pImplLib->mbPasswordProtected )
+ {
+ throw IllegalArgumentException("!passwordProtected", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ bool bRet = pImplLib->mbPasswordVerified;
+ return bRet;
+}
+
+sal_Bool SAL_CALL SfxScriptLibraryContainer::verifyLibraryPassword
+ ( const OUString& Name, const OUString& Password )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ if( !pImplLib->mbPasswordProtected || pImplLib->mbPasswordVerified )
+ {
+ throw IllegalArgumentException("!PasswordProtected || PasswordVerified", static_cast<cppu::OWeakObject*>(this), 1);
+ }
+ // Test password
+ bool bSuccess = false;
+ if( pImplLib->mbDoc50Password )
+ {
+ bSuccess = ( Password == pImplLib->maPassword );
+ if( bSuccess )
+ {
+ pImplLib->mbPasswordVerified = true;
+ }
+ }
+ else
+ {
+ pImplLib->maPassword = Password;
+ bSuccess = implLoadPasswordLibrary( pImplLib, Name, true );
+ if( bSuccess )
+ {
+ // The library gets modified by verifying the password, because other-
+ // wise for saving the storage would be copied and that doesn't work
+ // with mtg's storages when the password is verified
+ pImplLib->implSetModified( true );
+ pImplLib->mbPasswordVerified = true;
+
+ // Reload library to get source
+ if( pImplLib->mbLoaded )
+ {
+ implLoadPasswordLibrary( pImplLib, Name );
+ }
+ }
+ }
+ return bSuccess;
+}
+
+void SAL_CALL SfxScriptLibraryContainer::changeLibraryPassword( const OUString& Name,
+ const OUString& OldPassword,
+ const OUString& NewPassword )
+{
+ LibraryContainerMethodGuard aGuard( *this );
+ SfxLibrary* pImplLib = getImplLib( Name );
+ if( OldPassword == NewPassword )
+ {
+ return;
+ }
+ bool bOldPassword = !OldPassword.isEmpty();
+ bool bNewPassword = !NewPassword.isEmpty();
+ bool bStorage = mxStorage.is() && !pImplLib->mbLink;
+
+ if( pImplLib->mbReadOnly || (bOldPassword && !pImplLib->mbPasswordProtected) )
+ {
+ throw IllegalArgumentException();
+ }
+ // Library must be loaded
+ loadLibrary( Name );
+
+ bool bKillCryptedFiles = false;
+ bool bKillUnencryptedFiles = false;
+
+ // Remove or change password?
+ if( bOldPassword )
+ {
+ if( isLibraryPasswordVerified( Name ) )
+ {
+ if( pImplLib->maPassword != OldPassword )
+ {
+ throw IllegalArgumentException();
+ }
+ }
+ else
+ {
+ if( !verifyLibraryPassword( Name, OldPassword ) )
+ {
+ throw IllegalArgumentException();
+ }
+ // Reload library to get source
+ // Should be done in verifyLibraryPassword loadLibrary( Name );
+ }
+
+ if( !bNewPassword )
+ {
+ pImplLib->mbPasswordProtected = false;
+ pImplLib->mbPasswordVerified = false;
+ pImplLib->maPassword.clear();
+
+ maModifiable.setModified( true );
+ pImplLib->implSetModified( true );
+
+ if( !bStorage && !pImplLib->mbDoc50Password )
+ {
+ // Store application basic unencrypted
+ uno::Reference< embed::XStorage > xStorage;
+ storeLibraries_Impl( xStorage, false );
+ bKillCryptedFiles = true;
+ }
+ }
+ }
+
+ // Set new password?
+ if( bNewPassword )
+ {
+ pImplLib->mbPasswordProtected = true;
+ pImplLib->mbPasswordVerified = true;
+ pImplLib->maPassword = NewPassword;
+ SfxScriptLibrary *const pSL(dynamic_cast<SfxScriptLibrary *>(pImplLib));
+ if (pSL && pSL->mbLoaded)
+ {
+ pSL->mbLoadedSource = true; // must store source code now!
+ }
+
+ maModifiable.setModified( true );
+ pImplLib->implSetModified( true );
+
+ if( !bStorage && !pImplLib->mbDoc50Password )
+ {
+ // Store application basic crypted
+ uno::Reference< embed::XStorage > xStorage;
+ storeLibraries_Impl( xStorage, false );
+ bKillUnencryptedFiles = true;
+ }
+ }
+
+ if( !(bKillCryptedFiles || bKillUnencryptedFiles) )
+ return;
+
+ Sequence< OUString > aElementNames = pImplLib->getElementNames();
+ sal_Int32 nNameCount = aElementNames.getLength();
+ const OUString* pNames = aElementNames.getConstArray();
+ OUString aLibDirPath = createAppLibraryFolder( pImplLib, Name );
+ try
+ {
+ for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
+ {
+ OUString aElementName = pNames[ i ];
+
+ INetURLObject aElementInetObj( aLibDirPath );
+ aElementInetObj.insertName( aElementName, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ if( bKillUnencryptedFiles )
+ {
+ aElementInetObj.setExtension( maLibElementFileExtension );
+ }
+ else
+ {
+ aElementInetObj.setExtension( u"pba" );
+ }
+ OUString aElementPath( aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+
+ if( mxSFI->exists( aElementPath ) )
+ {
+ mxSFI->kill( aElementPath );
+ }
+ }
+ }
+ catch(const Exception& ) {}
+}
+
+
+static void setStreamKey( const uno::Reference< io::XStream >& xStream, const OUString& aPass )
+{
+ uno::Reference< embed::XEncryptionProtectedSource > xEncrStream( xStream, uno::UNO_QUERY );
+ if ( xEncrStream.is() )
+ {
+ xEncrStream->setEncryptionPassword( aPass );
+ }
+}
+
+
+// Impl methods
+bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib,
+ const OUString& aName,
+ const uno::Reference< embed::XStorage >& xStorage,
+ const css::uno::Reference< css::task::XInteractionHandler >& xHandler )
+{
+ Reference< XSimpleFileAccess3 > xDummySFA;
+ return implStorePasswordLibrary( pLib, aName, xStorage, OUString(), xDummySFA, xHandler );
+}
+
+bool SfxScriptLibraryContainer::implStorePasswordLibrary( SfxLibrary* pLib, const OUString& aName,
+ const css::uno::Reference< css::embed::XStorage >& xStorage,
+ const OUString& aTargetURL,
+ const Reference< XSimpleFileAccess3 >& rToUseSFI,
+ const css::uno::Reference< css::task::XInteractionHandler >& xHandler )
+{
+ bool bExport = !aTargetURL.isEmpty();
+
+ BasicManager* pBasicMgr = getBasicManager();
+ OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implStorePasswordLibrary: cannot do this without a BasicManager!" );
+ if ( !pBasicMgr )
+ {
+ return false;
+ }
+ // Only need to handle the export case here,
+ // save/saveas etc are handled in sfxbasemodel::storeSelf &
+ // sfxbasemodel::impl_store
+ std::vector<OUString> aNames;
+ if ( bExport && pBasicMgr->LegacyPsswdBinaryLimitExceeded(aNames) )
+ {
+ if ( xHandler.is() )
+ {
+ rtl::Reference<ModuleSizeExceeded> pReq = new ModuleSizeExceeded( aNames );
+ xHandler->handle( pReq );
+ if ( pReq->isAbort() )
+ {
+ throw util::VetoException();
+ }
+ }
+ }
+
+ StarBASIC* pBasicLib = pBasicMgr->GetLib( aName );
+ if( !pBasicLib )
+ {
+ return false;
+ }
+ Sequence< OUString > aElementNames = pLib->getElementNames();
+ sal_Int32 nNameCount = aElementNames.getLength();
+ const OUString* pNames = aElementNames.getConstArray();
+
+ bool bLink = pLib->mbLink;
+ bool bStorage = xStorage.is() && !bLink;
+ if( bStorage )
+ {
+ for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
+ {
+ OUString aElementName = pNames[ i ];
+
+ // Write binary image stream
+ SbModule* pMod = pBasicLib->FindModule( aElementName );
+ if( pMod )
+ {
+ OUString aCodeStreamName = aElementName + ".bin";
+ try
+ {
+ uno::Reference< io::XStream > xCodeStream = xStorage->openStreamElement(
+ aCodeStreamName,
+ embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+
+ if ( !xCodeStream.is() )
+ {
+ throw uno::RuntimeException("null returned from openStreamElement");
+ }
+ SvMemoryStream aMemStream;
+ /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
+
+ sal_Int32 const nSize = aMemStream.Tell();
+ if (nSize < 0) { abort(); }
+ Sequence< sal_Int8 > aBinSeq( nSize );
+ sal_Int8* pData = aBinSeq.getArray();
+ memcpy( pData, aMemStream.GetData(), nSize );
+
+ Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
+ if ( !xOut.is() )
+ {
+ throw io::IOException(); // access denied because the stream is readonly
+ }
+ xOut->writeBytes( aBinSeq );
+ xOut->closeOutput();
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: handle error
+ }
+ }
+
+ if( pLib->mbPasswordVerified || pLib->mbDoc50Password )
+ {
+ if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
+ {
+ SAL_WARN( "basic", "invalid library element '" << aElementName << "'.");
+ continue;
+ }
+
+ OUString aSourceStreamName = aElementName + ".xml";
+ try
+ {
+ uno::Reference< io::XStream > xSourceStream = xStorage->openStreamElement(
+ aSourceStreamName,
+ embed::ElementModes::READWRITE );
+ uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
+
+ // Set encryption key
+ setStreamKey( xSourceStream, pLib->maPassword );
+
+ Reference< XOutputStream > xOutput = xSourceStream->getOutputStream();
+ Reference< XNameContainer > xLib( pLib );
+ writeLibraryElement( xLib, aElementName, xOutput );
+ }
+ catch(const uno::Exception& )
+ {
+ OSL_FAIL( "Problem on storing of password library!" );
+ // TODO: error handling
+ }
+ }
+ else // !mbPasswordVerified
+ {
+ // TODO
+ // What to do if not verified?! In any case it's already loaded here
+ }
+ }
+
+ }
+ // Application libraries have only to be saved if the password
+ // is verified because otherwise they can't be modified
+ else if( pLib->mbPasswordVerified || bExport )
+ {
+ try
+ {
+ Reference< XSimpleFileAccess3 > xSFI = mxSFI;
+ if( rToUseSFI.is() )
+ {
+ xSFI = rToUseSFI;
+ }
+ OUString aLibDirPath;
+ if( bExport )
+ {
+ INetURLObject aInetObj( aTargetURL );
+ aInetObj.insertName( aName, true, INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aLibDirPath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( !xSFI->isFolder( aLibDirPath ) )
+ {
+ xSFI->createFolder( aLibDirPath );
+ }
+ }
+ else
+ {
+ aLibDirPath = createAppLibraryFolder( pLib, aName );
+ }
+
+ for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
+ {
+ OUString aElementName = pNames[ i ];
+
+ INetURLObject aElementInetObj( aLibDirPath );
+ aElementInetObj.insertName( aElementName, false,
+ INetURLObject::LAST_SEGMENT,
+ INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( u"pba" );
+ OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if( !isLibraryElementValid( pLib->getByName( aElementName ) ) )
+ {
+ SAL_WARN( "basic", "invalid library element '" << aElementName << "'.");
+ continue;
+ }
+
+ try
+ {
+ uno::Reference< embed::XStorage > xElementRootStorage =
+ ::comphelper::OStorageHelper::GetStorageFromURL(
+ aElementPath,
+ embed::ElementModes::READWRITE );
+ if ( !xElementRootStorage.is() )
+ {
+ throw uno::RuntimeException("null returned from GetStorageFromURL");
+ }
+ // Write binary image stream
+ SbModule* pMod = pBasicLib->FindModule( aElementName );
+ if( pMod )
+ {
+ uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
+ "code.bin",
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
+
+ SvMemoryStream aMemStream;
+ /*sal_Bool bStore = */pMod->StoreBinaryData( aMemStream );
+
+ sal_Int32 const nSize = aMemStream.Tell();
+ if (nSize < 0) { abort(); }
+ Sequence< sal_Int8 > aBinSeq( nSize );
+ sal_Int8* pData = aBinSeq.getArray();
+ memcpy( pData, aMemStream.GetData(), nSize );
+
+ Reference< XOutputStream > xOut = xCodeStream->getOutputStream();
+ if ( xOut.is() )
+ {
+ xOut->writeBytes( aBinSeq );
+ xOut->closeOutput();
+ }
+ }
+
+ // Write encrypted source stream
+ OUString aSourceStreamName( "source.xml" );
+
+ uno::Reference< io::XStream > xSourceStream;
+ try
+ {
+ xSourceStream = xElementRootStorage->openStreamElement(
+ aSourceStreamName,
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE );
+
+ // #87671 Allow encryption
+ uno::Reference< embed::XEncryptionProtectedSource > xEncr( xSourceStream, uno::UNO_QUERY_THROW );
+ xEncr->setEncryptionPassword( pLib->maPassword );
+ }
+ catch(const css::packages::WrongPasswordException& )
+ {
+ xSourceStream = xElementRootStorage->openEncryptedStreamElement(
+ aSourceStreamName,
+ embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE,
+ pLib->maPassword );
+ }
+
+ uno::Reference< beans::XPropertySet > xProps( xSourceStream, uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue("MediaType", uno::Any( OUString( "text/xml" ) ) );
+
+ Reference< XOutputStream > xOut = xSourceStream->getOutputStream();
+ Reference< XNameContainer > xLib( pLib );
+ writeLibraryElement( xLib, aElementName, xOut );
+ // i50568: sax writer already closes stream
+ // xOut->closeOutput();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xElementRootStorage, uno::UNO_QUERY_THROW );
+ xTransact->commit();
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: handle error
+ }
+
+ }
+ }
+ catch(const Exception& )
+ {
+ }
+ }
+ return true;
+}
+
+bool SfxScriptLibraryContainer::implLoadPasswordLibrary
+ ( SfxLibrary* pLib, const OUString& Name, bool bVerifyPasswordOnly )
+{
+ bool bRet = true;
+
+ bool bLink = pLib->mbLink;
+ bool bStorage = mxStorage.is() && !bLink;
+
+ // Already loaded? Then only verifiedPassword can change something
+ SfxScriptLibrary* pScriptLib = static_cast< SfxScriptLibrary* >( pLib );
+ if( pScriptLib->mbLoaded )
+ {
+ if( pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly &&
+ (pScriptLib->mbLoadedSource || !pLib->mbPasswordVerified) )
+ {
+ return false;
+ }
+ }
+
+ StarBASIC* pBasicLib = nullptr;
+ bool bLoadBinary = false;
+ if( !pScriptLib->mbLoadedBinary && !bVerifyPasswordOnly && !pLib->mbPasswordVerified )
+ {
+ BasicManager* pBasicMgr = getBasicManager();
+ OSL_ENSURE( pBasicMgr, "SfxScriptLibraryContainer::implLoadPasswordLibrary: cannot do this without a BasicManager!" );
+ bool bLoaded = pScriptLib->mbLoaded;
+ pScriptLib->mbLoaded = true; // Necessary to get lib
+ pBasicLib = pBasicMgr ? pBasicMgr->GetLib( Name ) : nullptr;
+ pScriptLib->mbLoaded = bLoaded; // Restore flag
+ if( !pBasicLib )
+ {
+ return false;
+ }
+ bLoadBinary = true;
+ pScriptLib->mbLoadedBinary = true;
+ }
+
+ bool bLoadSource = false;
+ if( !pScriptLib->mbLoadedSource && pLib->mbPasswordVerified && !bVerifyPasswordOnly )
+ {
+ bLoadSource = true;
+ pScriptLib->mbLoadedSource = true;
+ }
+
+ Sequence< OUString > aElementNames = pLib->getElementNames();
+ sal_Int32 nNameCount = aElementNames.getLength();
+ const OUString* pNames = aElementNames.getConstArray();
+
+ if( bStorage )
+ {
+ uno::Reference< embed::XStorage > xLibrariesStor;
+ uno::Reference< embed::XStorage > xLibraryStor;
+ try {
+ xLibrariesStor = mxStorage->openStorageElement( maLibrariesDir, embed::ElementModes::READ );
+ if ( !xLibrariesStor.is() )
+ {
+ throw uno::RuntimeException("null returned from openStorageElement");
+ }
+ xLibraryStor = xLibrariesStor->openStorageElement( Name, embed::ElementModes::READ );
+ if ( !xLibraryStor.is() )
+ {
+ throw uno::RuntimeException("null returned from openStorageElement");
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ OSL_FAIL( "### couldn't open sub storage for library" );
+ return false;
+ }
+
+ for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
+ {
+ OUString aElementName = pNames[ i ];
+
+ // Load binary
+ if( bLoadBinary )
+ {
+ SbModule* pMod = pBasicLib->FindModule( aElementName );
+ if( !pMod )
+ {
+ pMod = pBasicLib->MakeModule( aElementName, OUString() );
+ pBasicLib->SetModified( false );
+ }
+
+ OUString aCodeStreamName= aElementName + ".bin";
+ try
+ {
+ uno::Reference< io::XStream > xCodeStream = xLibraryStor->openStreamElement(
+ aCodeStreamName,
+ embed::ElementModes::READ );
+ if ( !xCodeStream.is() )
+ {
+ throw uno::RuntimeException("null returned from openStreamElement");
+ }
+ std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
+ if ( !pStream || pStream->GetError() )
+ {
+ sal_uInt32 nError = sal_uInt32(pStream ? pStream->GetError() : ERRCODE_IO_GENERAL);
+ throw task::ErrorCodeIOException(
+ ("utl::UcbStreamHelper::CreateStream failed for \""
+ + aCodeStreamName + "\": 0x"
+ + OUString::number(nError, 16)),
+ uno::Reference< uno::XInterface >(), nError);
+ }
+
+ /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
+ // TODO: Check return value
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: error handling
+ }
+ }
+
+ // Load source
+ if( bLoadSource || bVerifyPasswordOnly )
+ {
+ // Access encrypted source stream
+ OUString aSourceStreamName = aElementName + ".xml";
+ try
+ {
+ uno::Reference< io::XStream > xSourceStream = xLibraryStor->openEncryptedStreamElement(
+ aSourceStreamName,
+ embed::ElementModes::READ,
+ pLib->maPassword );
+ if ( !xSourceStream.is() )
+ {
+ throw uno::RuntimeException("null returned from openEncryptedStreamElement");
+ }
+ // if this point is reached then the password is correct
+ if ( !bVerifyPasswordOnly )
+ {
+ uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
+ if ( !xInStream.is() )
+ {
+ throw io::IOException(); // read access denied, seems to be impossible
+ }
+ Reference< XNameContainer > xLib( pLib );
+ Any aAny = importLibraryElement( xLib,
+ aElementName, aSourceStreamName,
+ xInStream );
+ if( pLib->hasByName( aElementName ) )
+ {
+ if( aAny.hasValue() )
+ {
+ pLib->maNameContainer->replaceByName( aElementName, aAny );
+ }
+ }
+ else
+ {
+ pLib->maNameContainer->insertByName( aElementName, aAny );
+ }
+ }
+ }
+ catch(const uno::Exception& )
+ {
+ bRet = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ OUString aLibDirPath = createAppLibraryFolder( pLib, Name );
+
+ for( sal_Int32 i = 0 ; i < nNameCount ; i++ )
+ {
+ OUString aElementName = pNames[ i ];
+
+ INetURLObject aElementInetObj( aLibDirPath );
+ aElementInetObj.insertName( aElementName, false,
+ INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All );
+ aElementInetObj.setExtension( u"pba" );
+ OUString aElementPath = aElementInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ uno::Reference< embed::XStorage > xElementRootStorage;
+ try
+ {
+ xElementRootStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
+ aElementPath,
+ embed::ElementModes::READ );
+ } catch(const uno::Exception& )
+ {
+ // TODO: error handling
+ }
+
+ if ( xElementRootStorage.is() )
+ {
+ // Load binary
+ if( bLoadBinary )
+ {
+ SbModule* pMod = pBasicLib->FindModule( aElementName );
+ if( !pMod )
+ {
+ pMod = pBasicLib->MakeModule( aElementName, OUString() );
+ pBasicLib->SetModified( false );
+ }
+
+ try
+ {
+ uno::Reference< io::XStream > xCodeStream = xElementRootStorage->openStreamElement(
+ "code.bin",
+ embed::ElementModes::READ );
+
+ std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( xCodeStream ));
+ if ( !pStream || pStream->GetError() )
+ {
+ sal_uInt32 nError = sal_uInt32(pStream ? pStream->GetError() : ERRCODE_IO_GENERAL);
+ throw task::ErrorCodeIOException(
+ ("utl::UcbStreamHelper::CreateStream failed"
+ " for code.bin: 0x"
+ + OUString::number(nError, 16)),
+ uno::Reference< uno::XInterface >(),
+ nError);
+ }
+
+ /*sal_Bool bRet = */pMod->LoadBinaryData( *pStream );
+ // TODO: Check return value
+ }
+ catch(const uno::Exception& )
+ {
+ // TODO: error handling
+ }
+ }
+
+ // Load source
+ if( bLoadSource || bVerifyPasswordOnly )
+ {
+ // Access encrypted source stream
+ try
+ {
+ OUString aSourceStreamName( "source.xml" );
+ uno::Reference< io::XStream > xSourceStream = xElementRootStorage->openEncryptedStreamElement(
+ aSourceStreamName,
+ embed::ElementModes::READ,
+ pLib->maPassword );
+ if ( !xSourceStream.is() )
+ {
+ throw uno::RuntimeException("null returned from openEncryptedStreamElement");
+ }
+ if ( !bVerifyPasswordOnly )
+ {
+ uno::Reference< io::XInputStream > xInStream = xSourceStream->getInputStream();
+ if ( !xInStream.is() )
+ {
+ throw io::IOException(); // read access denied, seems to be impossible
+ }
+ Reference< XNameContainer > xLib( pLib );
+ Any aAny = importLibraryElement( xLib,
+ aElementName,
+ aSourceStreamName,
+ xInStream );
+ if( pLib->hasByName( aElementName ) )
+ {
+ if( aAny.hasValue() )
+ {
+ pLib->maNameContainer->replaceByName( aElementName, aAny );
+ }
+ }
+ else
+ {
+ pLib->maNameContainer->insertByName( aElementName, aAny );
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ bRet = false;
+ }
+ }
+ }
+ }
+ }
+ catch(const Exception& )
+ {
+ // TODO
+ //throw e;
+ }
+ }
+
+ return bRet;
+}
+
+
+void SfxScriptLibraryContainer::onNewRootStorage()
+{
+}
+
+sal_Bool SAL_CALL SfxScriptLibraryContainer:: HasExecutableCode( const OUString& Library )
+{
+ BasicManager* pBasicMgr = getBasicManager();
+ OSL_ENSURE( pBasicMgr, "we need a basicmanager, really we do" );
+ if ( pBasicMgr )
+ {
+ return pBasicMgr->HasExeCode( Library ); // need to change this to take name
+ }
+ // default to it has code if we can't decide
+ return true;
+}
+
+
+// Service
+OUString SAL_CALL SfxScriptLibraryContainer::getImplementationName( )
+{
+ return "com.sun.star.comp.sfx2.ScriptLibraryContainer";
+}
+
+Sequence< OUString > SAL_CALL SfxScriptLibraryContainer::getSupportedServiceNames( )
+{
+ return {"com.sun.star.script.DocumentScriptLibraryContainer",
+ "com.sun.star.script.ScriptLibraryContainer"}; // for compatibility
+}
+
+// Implementation class SfxScriptLibrary
+
+// Ctor
+SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
+ const Reference< XSimpleFileAccess3 >& xSFI )
+ : SfxLibrary( _rModifiable, cppu::UnoType<OUString>::get(), xSFI )
+ , mbLoadedSource( false )
+ , mbLoadedBinary( false )
+{
+}
+
+SfxScriptLibrary::SfxScriptLibrary( ModifiableHelper& _rModifiable,
+ const Reference< XSimpleFileAccess3 >& xSFI,
+ const OUString& aLibInfoFileURL,
+ const OUString& aStorageURL,
+ bool ReadOnly )
+ : SfxLibrary( _rModifiable, cppu::UnoType<OUString>::get(), xSFI,
+ aLibInfoFileURL, aStorageURL, ReadOnly)
+ , mbLoadedSource( false )
+ , mbLoadedBinary( false )
+{
+}
+
+bool SfxScriptLibrary::isLoadedStorable()
+{
+ // note: mbLoadedSource can only be true for password-protected lib!
+ return SfxLibrary::isLoadedStorable() && (!mbPasswordProtected || mbLoadedSource);
+}
+
+// Provide modify state including resources
+bool SfxScriptLibrary::isModified()
+{
+ return implIsModified(); // No resources
+}
+
+void SfxScriptLibrary::storeResources()
+{
+ // No resources
+}
+
+void SfxScriptLibrary::storeResourcesToURL( const OUString&,
+ const Reference< task::XInteractionHandler >& )
+{}
+
+void SfxScriptLibrary::storeResourcesAsURL
+ ( const OUString&, const OUString& )
+{}
+
+void SfxScriptLibrary::storeResourcesToStorage( const css::uno::Reference
+ < css::embed::XStorage >& )
+{
+ // No resources
+}
+
+bool SfxScriptLibrary::containsValidModule(const Any& rElement)
+{
+ OUString sModuleText;
+ rElement >>= sModuleText;
+ return ( !sModuleText.isEmpty() );
+}
+
+bool SfxScriptLibrary::isLibraryElementValid(const css::uno::Any& rElement) const
+{
+ return SfxScriptLibrary::containsValidModule(rElement);
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( SfxScriptLibrary, SfxLibrary, SfxScriptLibrary_BASE );
+
+script::ModuleInfo SAL_CALL SfxScriptLibrary::getModuleInfo( const OUString& ModuleName )
+{
+ if ( !hasModuleInfo( ModuleName ) )
+ {
+ throw NoSuchElementException();
+ }
+ return mModuleInfo[ ModuleName ];
+}
+
+sal_Bool SAL_CALL SfxScriptLibrary::hasModuleInfo( const OUString& ModuleName )
+{
+ bool bRes = false;
+ ModuleInfoMap::iterator it = mModuleInfo.find( ModuleName );
+
+ if ( it != mModuleInfo.end() )
+ {
+ bRes = true;
+ }
+ return bRes;
+}
+
+void SAL_CALL SfxScriptLibrary::insertModuleInfo( const OUString& ModuleName, const script::ModuleInfo& ModuleInfo )
+{
+ if ( hasModuleInfo( ModuleName ) )
+ {
+ throw ElementExistException();
+ }
+ mModuleInfo[ ModuleName ] = ModuleInfo;
+}
+
+void SAL_CALL SfxScriptLibrary::removeModuleInfo( const OUString& ModuleName )
+{
+ // #FIXME add NoSuchElementException to the spec
+ if ( mModuleInfo.erase( ModuleName ) == 0 )
+ throw NoSuchElementException();
+}
+
+} // namespace basic
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_sfx2_ScriptLibraryContainer_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new basic::SfxScriptLibraryContainer());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */