summaryrefslogtreecommitdiffstats
path: root/scripting/source/provider
diff options
context:
space:
mode:
Diffstat (limited to 'scripting/source/provider')
-rw-r--r--scripting/source/provider/ActiveMSPList.cxx295
-rw-r--r--scripting/source/provider/ActiveMSPList.hxx94
-rw-r--r--scripting/source/provider/BrowseNodeFactoryImpl.cxx650
-rw-r--r--scripting/source/provider/BrowseNodeFactoryImpl.hxx70
-rw-r--r--scripting/source/provider/MasterScriptProvider.cxx676
-rw-r--r--scripting/source/provider/MasterScriptProvider.hxx131
-rw-r--r--scripting/source/provider/MasterScriptProviderFactory.cxx85
-rw-r--r--scripting/source/provider/MasterScriptProviderFactory.hxx74
-rw-r--r--scripting/source/provider/ProviderCache.cxx203
-rw-r--r--scripting/source/provider/ProviderCache.hxx80
-rw-r--r--scripting/source/provider/URIHelper.cxx256
-rw-r--r--scripting/source/provider/URIHelper.hxx87
12 files changed, 2701 insertions, 0 deletions
diff --git a/scripting/source/provider/ActiveMSPList.cxx b/scripting/source/provider/ActiveMSPList.cxx
new file mode 100644
index 0000000000..fbd2b2b053
--- /dev/null
+++ b/scripting/source/provider/ActiveMSPList.cxx
@@ -0,0 +1,295 @@
+/* -*- 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 <cppuhelper/exc_hlp.hxx>
+#include <util/MiscUtils.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include "ActiveMSPList.hxx"
+
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+using namespace ::sf_misc;
+
+namespace func_provider
+{
+
+ActiveMSPList::ActiveMSPList( const Reference< XComponentContext > & xContext ) : m_xContext( xContext )
+{
+ userDirString = "user";
+ shareDirString = "share";
+ bundledDirString = "bundled";
+}
+
+ActiveMSPList::~ActiveMSPList()
+{
+}
+
+Reference< provider::XScriptProvider >
+ActiveMSPList::createNewMSP( const uno::Any& context )
+{
+ Sequence< Any > args( &context, 1 );
+
+ Reference< provider::XScriptProvider > msp(
+ m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.script.provider.MasterScriptProvider", args, m_xContext ), UNO_QUERY );
+ return msp;
+}
+
+class NonDocMSPCreator
+{
+public:
+ explicit NonDocMSPCreator(ActiveMSPList *pList)
+ {
+ pList->createNonDocMSPs();
+ }
+};
+
+namespace
+{
+ //thread-safe method to ensure createNonDocMSPs is called once
+ void ensureNonDocMSPs(ActiveMSPList *pList)
+ {
+ static NonDocMSPCreator theCreator(pList);
+ }
+}
+
+Reference< provider::XScriptProvider >
+ActiveMSPList::getMSPFromAnyContext( const Any& aContext )
+{
+ Reference< provider::XScriptProvider > msp;
+ OUString sContext;
+ if ( aContext >>= sContext )
+ {
+ msp = getMSPFromStringContext( sContext );
+ return msp;
+ }
+
+ Reference< frame::XModel > xModel( aContext, UNO_QUERY );
+
+ Reference< document::XScriptInvocationContext > xScriptContext( aContext, UNO_QUERY );
+ if ( xScriptContext.is() )
+ {
+ try
+ {
+ // the component supports executing scripts embedded in a - possibly foreign document.
+ // Check whether this other document it's the component itself.
+ if ( !xModel.is() || ( xModel != xScriptContext->getScriptContainer() ) )
+ {
+ msp = getMSPFromInvocationContext( xScriptContext );
+ return msp;
+ }
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ xModel.set( Reference< frame::XModel >() );
+ }
+ }
+
+ if ( xModel.is() )
+ {
+ sContext = MiscUtils::xModelToTdocUrl( xModel, m_xContext );
+ msp = getMSPFromStringContext( sContext );
+ return msp;
+ }
+
+ ensureNonDocMSPs(this);
+ return m_hMsps[ shareDirString ];
+}
+
+Reference< provider::XScriptProvider >
+ ActiveMSPList::getMSPFromInvocationContext( const Reference< document::XScriptInvocationContext >& xContext )
+{
+ Reference< provider::XScriptProvider > msp;
+
+ Reference< document::XEmbeddedScripts > xScripts;
+ if ( xContext.is() )
+ xScripts.set( xContext->getScriptContainer() );
+ if ( !xScripts.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "Failed to create MasterScriptProvider for ScriptInvocationContext: "
+ "Component supporting XEmbeddScripts interface not found.",
+ nullptr, 1 );
+ }
+
+ ::osl::MutexGuard guard( m_mutex );
+
+ Reference< XInterface > xNormalized( xContext, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos == m_mScriptComponents.end() )
+ {
+ // TODO
+ msp = createNewMSP( uno::Any( xContext ) );
+ addActiveMSP( xNormalized, msp );
+ }
+ else
+ {
+ msp = pos->second;
+ }
+
+ return msp;
+}
+
+Reference< provider::XScriptProvider >
+ ActiveMSPList::getMSPFromStringContext( const OUString& context )
+{
+ Reference< provider::XScriptProvider > msp;
+ try
+ {
+ if ( context.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ Reference< frame::XModel > xModel( MiscUtils::tDocUrlToModel( context ) );
+
+ Reference< document::XEmbeddedScripts > xScripts( xModel, UNO_QUERY );
+ Reference< document::XScriptInvocationContext > xScriptsContext( xModel, UNO_QUERY );
+ if ( !xScripts.is() && !xScriptsContext.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "Failed to create MasterScriptProvider for '"
+ + context +
+ "': Either XEmbeddScripts or XScriptInvocationContext need to be supported by the document.",
+ nullptr, 1 );
+ }
+
+ ::osl::MutexGuard guard( m_mutex );
+ Reference< XInterface > xNormalized( xModel, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos == m_mScriptComponents.end() )
+ {
+ msp = createNewMSP( context );
+ addActiveMSP( xNormalized, msp );
+ }
+ else
+ {
+ msp = pos->second;
+ }
+ }
+ else
+ {
+ ::osl::MutexGuard guard( m_mutex );
+ Msp_hash::iterator h_itEnd = m_hMsps.end();
+ Msp_hash::const_iterator itr = m_hMsps.find( context );
+ if ( itr == h_itEnd )
+ {
+ msp = createNewMSP( context );
+ m_hMsps[ context ] = msp;
+ }
+ else
+ {
+ msp = m_hMsps[ context ];
+ }
+ }
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ // allowed to leave
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave
+ }
+ catch( const Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "Failed to create MasterScriptProvider for context '"
+ + context + "'.",
+ *this, anyEx );
+ }
+ return msp;
+}
+
+void
+ActiveMSPList::addActiveMSP( const Reference< uno::XInterface >& xComponent,
+ const Reference< provider::XScriptProvider >& msp )
+{
+ ::osl::MutexGuard guard( m_mutex );
+ Reference< XInterface > xNormalized( xComponent, UNO_QUERY );
+ ScriptComponent_map::const_iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos != m_mScriptComponents.end() )
+ return;
+
+ m_mScriptComponents[ xNormalized ] = msp;
+
+ // add self as listener for component disposal
+ // should probably throw from this method!!, reexamine
+ try
+ {
+ Reference< lang::XComponent > xBroadcaster( xComponent, UNO_QUERY_THROW );
+ xBroadcaster->addEventListener( this );
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+}
+
+
+void SAL_CALL ActiveMSPList::disposing( const css::lang::EventObject& Source )
+
+{
+ try
+ {
+ Reference< XInterface > xNormalized( Source.Source, UNO_QUERY );
+ if ( xNormalized.is() )
+ {
+ ::osl::MutexGuard guard( m_mutex );
+ ScriptComponent_map::iterator pos = m_mScriptComponents.find( xNormalized );
+ if ( pos != m_mScriptComponents.end() )
+ m_mScriptComponents.erase( pos );
+ }
+ }
+ catch ( const Exception& )
+ {
+ // if we get an exception here, there is not much we can do about
+ // it can't throw as it will screw up the model that is calling dispose
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+}
+
+void
+ActiveMSPList::createNonDocMSPs()
+{
+ // do creation of user and share MSPs here
+ OUString serviceName("com.sun.star.script.provider.MasterScriptProvider");
+
+ Sequence< Any > args{ Any(userDirString) };
+ Reference< provider::XScriptProvider > userMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ userDirString ] = userMsp;
+
+ args = { Any(shareDirString) };
+ Reference< provider::XScriptProvider > shareMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ shareDirString ] = shareMsp;
+
+ args = { Any(bundledDirString) };
+ Reference< provider::XScriptProvider > bundledMsp( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, m_xContext ), UNO_QUERY );
+ // should check if provider reference is valid
+ m_hMsps[ bundledDirString ] = bundledMsp;
+}
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ActiveMSPList.hxx b/scripting/source/provider/ActiveMSPList.hxx
new file mode 100644
index 0000000000..fb52629c1d
--- /dev/null
+++ b/scripting/source/provider/ActiveMSPList.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XEventListener.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <map>
+#include <unordered_map>
+
+namespace func_provider
+{
+
+//Typedefs
+typedef std::map < css::uno::Reference< css::uno::XInterface >
+ , css::uno::Reference< css::script::provider::XScriptProvider >
+ > ScriptComponent_map;
+
+typedef std::unordered_map< OUString,
+ css::uno::Reference< css::script::provider::XScriptProvider > > Msp_hash;
+
+class NonDocMSPCreator;
+
+class ActiveMSPList : public ::cppu::WeakImplHelper< css::lang::XEventListener >
+{
+
+public:
+
+ explicit ActiveMSPList( const css::uno::Reference<
+ css::uno::XComponentContext > & xContext );
+ virtual ~ActiveMSPList() override;
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromStringContext( const OUString& context );
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromAnyContext( const css::uno::Any& context );
+
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getMSPFromInvocationContext( const css::uno::Reference< css::document::XScriptInvocationContext >& context );
+
+ //XEventListener
+
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+private:
+ void addActiveMSP( const css::uno::Reference< css::uno::XInterface >& xComponent,
+ const css::uno::Reference< css::script::provider::XScriptProvider >& msp );
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createNewMSP( const css::uno::Any& context );
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createNewMSP( const OUString& context )
+ {
+ return createNewMSP( css::uno::Any( context ) );
+ }
+
+ friend class NonDocMSPCreator;
+ void createNonDocMSPs();
+
+ Msp_hash m_hMsps;
+ ScriptComponent_map m_mScriptComponents;
+ osl::Mutex m_mutex;
+ OUString userDirString;
+ OUString shareDirString;
+ OUString bundledDirString;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+};
+} // func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/BrowseNodeFactoryImpl.cxx b/scripting/source/provider/BrowseNodeFactoryImpl.cxx
new file mode 100644
index 0000000000..3ea45aeecd
--- /dev/null
+++ b/scripting/source/provider/BrowseNodeFactoryImpl.cxx
@@ -0,0 +1,650 @@
+/* -*- 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 <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/browse/BrowseNodeFactoryViewTypes.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+
+#include <comphelper/diagnose_ex.hxx>
+
+#include "BrowseNodeFactoryImpl.hxx"
+#include <util/MiscUtils.hxx>
+
+#include <vector>
+#include <algorithm>
+#include <memory>
+#include <optional>
+#include <string_view>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::sf_misc;
+
+namespace browsenodefactory
+{
+namespace {
+class BrowseNodeAggregator :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ OUString m_Name;
+ std::vector< Reference< browse::XBrowseNode > > m_Nodes;
+
+public:
+
+ explicit BrowseNodeAggregator( const Reference< browse::XBrowseNode >& node )
+ : m_Name(node->getName())
+ {
+ m_Nodes.resize( 1 );
+ m_Nodes[ 0 ] = node;
+ }
+
+ void addBrowseNode( const Reference< browse::XBrowseNode>& node )
+ {
+ m_Nodes.push_back( node );
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_Name;
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ std::vector< Sequence< Reference < browse::XBrowseNode > > > seqs;
+ seqs.reserve( m_Nodes.size() );
+
+ sal_Int32 numChildren = 0;
+
+ for (Reference<XBrowseNode> & xNode : m_Nodes)
+ {
+ Sequence< Reference < browse::XBrowseNode > > children;
+ try
+ {
+ children = xNode->getChildNodes();
+ seqs.push_back( children );
+ numChildren += children.getLength();
+ }
+ catch ( Exception& )
+ {
+ // some form of exception getting child nodes so they
+ // won't be displayed
+ }
+ }
+
+ Sequence< Reference < browse::XBrowseNode > > result( numChildren );
+ sal_Int32 index = 0;
+ for ( const Sequence< Reference < browse::XBrowseNode > >& children : seqs )
+ {
+ std::copy(children.begin(), children.end(), std::next(result.getArray(), index));
+ index += children.getLength();
+
+ if (index >= numChildren)
+ break;
+ }
+ return result;
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ for (Reference<XBrowseNode> & xNode : m_Nodes)
+ {
+ try
+ {
+ if ( xNode->hasChildNodes() )
+ {
+ return true;
+ }
+ }
+ catch ( Exception& )
+ {
+ // some form of exception getting child nodes so move
+ // on to the next one
+ }
+ }
+
+ return false;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+};
+
+struct alphaSort
+{
+ bool operator()( std::u16string_view a, std::u16string_view b )
+ {
+ return a.compare( b ) < 0;
+ }
+};
+class LocationBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ std::optional<std::unordered_map< OUString, Reference< browse::XBrowseNode > >> m_hBNA;
+ std::vector< OUString > m_vStr;
+ OUString m_sNodeName;
+ Reference< browse::XBrowseNode > m_origNode;
+
+public:
+
+ explicit LocationBrowseNode( const Reference< browse::XBrowseNode >& node )
+ : m_sNodeName(node->getName())
+ {
+ m_origNode.set( node );
+ }
+
+
+ // XBrowseNode
+
+ virtual OUString SAL_CALL getName() override
+ {
+ return m_sNodeName;
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ if ( !m_hBNA )
+ {
+ loadChildNodes();
+ }
+
+ Sequence< Reference< browse::XBrowseNode > > children( m_hBNA->size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 index = 0;
+
+ for ( const auto& str : m_vStr )
+ {
+ childrenRange[ index ].set( m_hBNA->find( str )->second );
+ ++index;
+ }
+
+ return children;
+ }
+
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return true;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+
+private:
+
+ void loadChildNodes()
+ {
+ m_hBNA.emplace();
+
+ const Sequence< Reference< browse::XBrowseNode > > langNodes =
+ m_origNode->getChildNodes();
+
+ for ( const auto& rLangNode : langNodes )
+ {
+ Reference< browse::XBrowseNode > xbn;
+ if ( rLangNode->getName() == "uno_packages" )
+ {
+ xbn.set( new LocationBrowseNode( rLangNode ) );
+ }
+ else
+ {
+ xbn.set( rLangNode );
+ }
+
+ const Sequence< Reference< browse::XBrowseNode > > grandchildren =
+ xbn->getChildNodes();
+
+ for ( const Reference< browse::XBrowseNode >& grandchild : grandchildren )
+ {
+ auto h_it =
+ m_hBNA->find( grandchild->getName() );
+
+ if ( h_it != m_hBNA->end() )
+ {
+ BrowseNodeAggregator* bna = static_cast< BrowseNodeAggregator* >( h_it->second.get() );
+ bna->addBrowseNode( grandchild );
+ }
+ else
+ {
+ Reference< browse::XBrowseNode > bna(
+ new BrowseNodeAggregator( grandchild ) );
+ (*m_hBNA)[ grandchild->getName() ].set( bna );
+ m_vStr.push_back( grandchild->getName() );
+ }
+ }
+ }
+ // sort children alphabetically
+ ::std::sort( m_vStr.begin(), m_vStr.end(), alphaSort() );
+ }
+};
+
+std::vector< Reference< browse::XBrowseNode > > getAllBrowseNodes( const Reference< XComponentContext >& xCtx )
+{
+ const Sequence< OUString > openDocs =
+ MiscUtils::allOpenTDocUrls( xCtx );
+
+ Reference< provider::XScriptProviderFactory > xFac;
+ sal_Int32 initialSize = openDocs.getLength() + 2;
+ sal_Int32 mspIndex = 0;
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs( initialSize );
+ try
+ {
+ xFac = provider::theMasterScriptProviderFactory::get( xCtx );
+
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( OUString("user") ) ), UNO_QUERY_THROW );
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( OUString("share") ) ), UNO_QUERY_THROW );
+ }
+ // TODO proper exception handling, should throw
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("scripting", "Caught" );
+ locnBNs.resize( mspIndex );
+ return locnBNs;
+ }
+
+ for ( const auto& rDoc : openDocs )
+ {
+ try
+ {
+ Reference< frame::XModel > model( MiscUtils::tDocUrlToModel( rDoc ), UNO_SET_THROW );
+
+ // #i44599 Check if it's a real document or something special like Hidden/Preview
+ css::uno::Reference< css::frame::XController > xCurrentController = model->getCurrentController();
+ if( xCurrentController.is() )
+ {
+ utl::MediaDescriptor aMD( model->getArgs() );
+ bool bDefault = false;
+ bool bHidden = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_HIDDEN, bDefault );
+ bool bPreview = aMD.getUnpackedValueOrDefault( utl::MediaDescriptor::PROP_PREVIEW, bDefault );
+ if( !bHidden && !bPreview )
+ {
+ Reference< document::XEmbeddedScripts > xScripts( model, UNO_QUERY );
+ if ( xScripts.is() )
+ locnBNs[ mspIndex++ ].set( xFac->createScriptProvider( Any( model ) ), UNO_QUERY_THROW );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+
+ }
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs_Return( mspIndex );
+ for ( sal_Int32 j = 0; j < mspIndex; j++ )
+ locnBNs_Return[j] = locnBNs[j];
+
+ return locnBNs_Return;
+}
+
+} // namespace
+
+typedef ::std::vector< Reference< browse::XBrowseNode > > vXBrowseNodes;
+
+namespace {
+
+struct alphaSortForBNodes
+{
+ bool operator()( const Reference< browse::XBrowseNode >& a, const Reference< browse::XBrowseNode >& b )
+ {
+ return a->getName().compareTo( b->getName() ) < 0;
+ }
+};
+
+}
+
+typedef ::cppu::WeakImplHelper< browse::XBrowseNode > t_BrowseNodeBase;
+
+namespace {
+
+class DefaultBrowseNode :
+ public t_BrowseNodeBase
+{
+
+private:
+ Reference< browse::XBrowseNode > m_xWrappedBrowseNode;
+ Reference< lang::XTypeProvider > m_xWrappedTypeProv;
+ Reference< XAggregation > m_xAggProxy;
+ Reference< XComponentContext > m_xCtx;
+
+public:
+ DefaultBrowseNode( const Reference< XComponentContext >& xCtx, const Reference< browse::XBrowseNode>& xNode ) : m_xWrappedBrowseNode( xNode ), m_xWrappedTypeProv( xNode, UNO_QUERY ), m_xCtx( xCtx )
+ {
+ OSL_ENSURE( m_xWrappedBrowseNode.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" );
+ OSL_ENSURE( m_xWrappedTypeProv.is(), "DefaultBrowseNode::DefaultBrowseNode(): No BrowseNode to wrap" );
+ OSL_ENSURE( m_xCtx.is(), "DefaultBrowseNode::DefaultBrowseNode(): No ComponentContext" );
+ // Use proxy factory service to create aggregatable proxy.
+ try
+ {
+ Reference< reflection::XProxyFactory > xProxyFac =
+ reflection::ProxyFactory::create( m_xCtx );
+ m_xAggProxy = xProxyFac->createProxy( m_xWrappedBrowseNode );
+ }
+ catch( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "scripting", "DefaultBrowseNode::DefaultBrowseNode" );
+ }
+ OSL_ENSURE( m_xAggProxy.is(),
+ "DefaultBrowseNode::DefaultBrowseNode: Wrapped BrowseNode cannot be aggregated!" );
+
+ if ( !m_xAggProxy.is() )
+ return;
+
+ osl_atomic_increment( &m_refCount );
+
+ /* i35609 - Fix crash on Solaris. The setDelegator call needs
+ to be in its own block to ensure that all temporary Reference
+ instances that are acquired during the call are released
+ before m_refCount is decremented again */
+ {
+ m_xAggProxy->setDelegator(
+ getXWeak() );
+ }
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ virtual ~DefaultBrowseNode() override
+ {
+ if ( m_xAggProxy.is() )
+ {
+ m_xAggProxy->setDelegator( uno::Reference< uno::XInterface >() );
+ }
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ if ( hasChildNodes() )
+ {
+ vXBrowseNodes aVNodes;
+ const Sequence < Reference< browse::XBrowseNode > > nodes =
+ m_xWrappedBrowseNode->getChildNodes();
+ for ( const Reference< browse::XBrowseNode >& xBrowseNode : nodes )
+ {
+ OSL_ENSURE( xBrowseNode.is(), "DefaultBrowseNode::getChildNodes(): Invalid BrowseNode" );
+ if( xBrowseNode.is() )
+ aVNodes.push_back( new DefaultBrowseNode( m_xCtx, xBrowseNode ) );
+ }
+
+ ::std::sort( aVNodes.begin(), aVNodes.end(), alphaSortForBNodes() );
+ Sequence < Reference< browse::XBrowseNode > > children( aVNodes.size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 i = 0;
+ for ( const auto& rxNode : aVNodes )
+ {
+ childrenRange[ i ].set( rxNode );
+ i++;
+ }
+ return children;
+ }
+ else
+ {
+ // no nodes
+
+ Sequence < Reference< browse::XBrowseNode > > none;
+ return none;
+ }
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return m_xWrappedBrowseNode->getType();
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_xWrappedBrowseNode->getName();
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ return m_xWrappedBrowseNode->hasChildNodes();
+ }
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type& aType ) override
+ {
+ Any aRet = t_BrowseNodeBase::queryInterface( aType );
+ if ( aRet.hasValue() )
+ {
+ return aRet;
+ }
+ if ( m_xAggProxy.is() )
+ {
+ return m_xAggProxy->queryAggregation( aType );
+ }
+ else
+ {
+ return Any();
+ }
+ }
+
+ // XTypeProvider (implemented by base, but needs to be overridden for
+ // delegating to aggregate)
+ virtual Sequence< Type > SAL_CALL getTypes() override
+ {
+ return m_xWrappedTypeProv->getTypes();
+ }
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+};
+
+class DefaultRootBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+
+private:
+ vXBrowseNodes m_vNodes;
+ OUString m_Name;
+
+public:
+ explicit DefaultRootBrowseNode( const Reference< XComponentContext >& xCtx )
+ {
+ std::vector< Reference< browse::XBrowseNode > > nodes =
+ getAllBrowseNodes( xCtx );
+
+ for (Reference< browse::XBrowseNode > & xNode : nodes)
+ {
+ m_vNodes.push_back( new DefaultBrowseNode( xCtx, xNode ) );
+ }
+ m_Name = "Root";
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+ // no need to sort user, share, doc1...docN
+ //::std::sort( m_vNodes.begin(), m_vNodes.end(), alphaSortForBNodes() );
+ Sequence < Reference< browse::XBrowseNode > > children( m_vNodes.size() );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 i = 0;
+ for ( const auto& rxNode : m_vNodes )
+ {
+ childrenRange[ i ].set( rxNode );
+ i++;
+ }
+ return children;
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::ROOT;
+ }
+
+ virtual OUString
+ SAL_CALL getName() override
+ {
+ return m_Name;
+ }
+
+ virtual sal_Bool SAL_CALL
+ hasChildNodes() override
+ {
+ bool result = true;
+ if ( m_vNodes.empty() )
+ {
+ result = false;
+ }
+ return result;
+ }
+};
+
+
+class SelectorBrowseNode :
+ public ::cppu::WeakImplHelper< browse::XBrowseNode >
+{
+private:
+ Reference< XComponentContext > m_xComponentContext;
+
+public:
+ explicit SelectorBrowseNode( const Reference< XComponentContext >& xContext )
+ : m_xComponentContext( xContext )
+ {
+ }
+
+ virtual OUString SAL_CALL getName() override
+ {
+ return "Root";
+ }
+
+ virtual Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+ getChildNodes() override
+ {
+
+ std::vector< Reference < browse::XBrowseNode > > locnBNs = getAllBrowseNodes( m_xComponentContext );
+
+ Sequence< Reference< browse::XBrowseNode > > children(
+ locnBNs.size() );
+ auto childrenRange = asNonConstRange(children);
+
+ for ( size_t j = 0; j < locnBNs.size(); j++ )
+ {
+ childrenRange[j] = new LocationBrowseNode( locnBNs[j] );
+ }
+
+ return children;
+ }
+
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return true; // will always be user and share
+ }
+
+ virtual sal_Int16 SAL_CALL getType() override
+ {
+ return browse::BrowseNodeTypes::CONTAINER;
+ }
+};
+
+}
+
+BrowseNodeFactoryImpl::BrowseNodeFactoryImpl(
+ Reference< XComponentContext > const & xComponentContext )
+ : m_xComponentContext( xComponentContext )
+{
+}
+
+BrowseNodeFactoryImpl::~BrowseNodeFactoryImpl()
+{
+}
+
+
+// Implementation of XBrowseNodeFactory
+
+
+/*
+ * The selector hierarchy is the standard hierarchy for organizers with the
+ * language nodes removed.
+ */
+Reference< browse::XBrowseNode > SAL_CALL
+BrowseNodeFactoryImpl::createView( sal_Int16 viewType )
+{
+ switch( viewType )
+ {
+ case browse::BrowseNodeFactoryViewTypes::MACROSELECTOR:
+ return new SelectorBrowseNode( m_xComponentContext );
+ case browse::BrowseNodeFactoryViewTypes::MACROORGANIZER:
+ return getOrganizerHierarchy();
+ default:
+ throw RuntimeException( "Unknown view type" );
+ }
+}
+
+Reference< browse::XBrowseNode >
+BrowseNodeFactoryImpl::getOrganizerHierarchy() const
+{
+ Reference< browse::XBrowseNode > xRet = new DefaultRootBrowseNode( m_xComponentContext );
+ return xRet;
+}
+
+// Implementation of XServiceInfo
+
+
+OUString SAL_CALL
+BrowseNodeFactoryImpl::getImplementationName()
+{
+ return "com.sun.star.script.browse.BrowseNodeFactory";
+}
+
+Sequence< OUString > SAL_CALL
+BrowseNodeFactoryImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.browse.BrowseNodeFactory" };
+}
+
+sal_Bool BrowseNodeFactoryImpl::supportsService(OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_BrowseNodeFactoryImpl_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new BrowseNodeFactoryImpl(context));
+}
+
+} // namespace browsenodefactory
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/BrowseNodeFactoryImpl.hxx b/scripting/source/provider/BrowseNodeFactoryImpl.hxx
new file mode 100644
index 0000000000..9085680210
--- /dev/null
+++ b/scripting/source/provider/BrowseNodeFactoryImpl.hxx
@@ -0,0 +1,70 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+#include <com/sun/star/script/browse/XBrowseNodeFactory.hpp>
+
+namespace browsenodefactory
+{
+
+class BrowseNodeFactoryImpl :
+ public ::cppu::WeakImplHelper <
+ css::script::browse::XBrowseNodeFactory,
+ css::lang::XServiceInfo >
+{
+private:
+ css::uno::Reference< css::uno::XComponentContext > m_xComponentContext;
+
+protected:
+ virtual ~BrowseNodeFactoryImpl() override;
+
+public:
+ explicit BrowseNodeFactoryImpl(
+ css::uno::Reference< css::uno::XComponentContext > const & xComponentContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( OUString const & serviceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XBrowseNodeFactory
+ virtual css::uno::Reference< css::script::browse::XBrowseNode > SAL_CALL
+ createView( sal_Int16 viewType ) override;
+private:
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::script::browse::XBrowseNode >
+ getOrganizerHierarchy() const;
+};
+
+
+} // namespace browsenodefactory
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProvider.cxx b/scripting/source/provider/MasterScriptProvider.cxx
new file mode 100644
index 0000000000..66fc58db78
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProvider.cxx
@@ -0,0 +1,676 @@
+/* -*- 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 <comphelper/SetFlagContextHelper.hxx>
+#include <comphelper/documentinfo.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/urlobj.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+
+#include <com/sun/star/deployment/XPackage.hpp>
+#include <com/sun/star/script/browse/BrowseNodeTypes.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp>
+
+#include <util/MiscUtils.hxx>
+#include <sal/log.hxx>
+
+#include "MasterScriptProvider.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::document;
+using namespace ::sf_misc;
+
+namespace func_provider
+{
+
+static bool endsWith( std::u16string_view target, std::u16string_view item )
+{
+ size_t index = target.find( item );
+ return index != std::u16string_view::npos &&
+ index == ( target.size() - item.size() );
+}
+
+/* should be available in some central location. */
+
+// XScriptProvider implementation
+
+
+MasterScriptProvider::MasterScriptProvider( const Reference< XComponentContext > & xContext ):
+ m_xContext( xContext ), m_bIsValid( false ), m_bInitialised( false ),
+ m_bIsPkgMSP( false )
+{
+ ENSURE_OR_THROW( m_xContext.is(), "MasterScriptProvider::MasterScriptProvider: No context available\n" );
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "MasterScriptProvider::MasterScriptProvider: No service manager available\n" );
+ m_bIsValid = true;
+}
+
+
+MasterScriptProvider::~MasterScriptProvider()
+{
+}
+
+
+void SAL_CALL MasterScriptProvider::initialize( const Sequence < Any >& args )
+{
+ if ( m_bInitialised )
+ return;
+
+ m_bIsValid = false;
+
+ sal_Int32 len = args.getLength();
+ if ( len > 1 )
+ {
+ throw RuntimeException(
+ "MasterScriptProvider::initialize: invalid number of arguments" );
+ }
+
+ Sequence< Any > invokeArgs( len );
+
+ if ( len != 0 )
+ {
+ auto pinvokeArgs = invokeArgs.getArray();
+ // check if first parameter is a string
+ // if it is, this implies that this is a MSP created
+ // with a user or share ctx ( used for browse functionality )
+
+ if ( args[ 0 ] >>= m_sCtxString )
+ {
+ pinvokeArgs[ 0 ] = args[ 0 ];
+ if ( m_sCtxString.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ m_xModel = MiscUtils::tDocUrlToModel( m_sCtxString );
+ }
+ }
+ else if ( args[ 0 ] >>= m_xInvocationContext )
+ {
+ m_xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ args[ 0 ] >>= m_xModel;
+ }
+
+ if ( m_xModel.is() )
+ {
+ // from the arguments, we were able to deduce a model. That alone doesn't
+ // suffice, we also need an XEmbeddedScripts which actually indicates support
+ // for embedding scripts
+ Reference< XEmbeddedScripts > xScripts( m_xModel, UNO_QUERY );
+ if ( !xScripts.is() )
+ {
+ throw lang::IllegalArgumentException(
+ "The given document does not support embedding scripts into it, and cannot be associated with such a document.",
+ *this,
+ 1
+ );
+ }
+
+ try
+ {
+ m_sCtxString = MiscUtils::xModelToTdocUrl( m_xModel, m_xContext );
+ }
+ catch ( const Exception& )
+ {
+ Any aError( ::cppu::getCaughtException() );
+
+ Exception aException;
+ aError >>= aException;
+ OUString buf =
+ "MasterScriptProvider::initialize: caught " +
+ aError.getValueTypeName() +
+ ":" +
+ aException.Message;
+ throw lang::WrappedTargetException( buf, *this, aError );
+ }
+
+ if ( m_xInvocationContext.is() && m_xInvocationContext != m_xModel )
+ pinvokeArgs[ 0 ] <<= m_xInvocationContext;
+ else
+ pinvokeArgs[ 0 ] <<= m_sCtxString;
+ }
+
+ OUString pkgSpec = "uno_packages";
+ sal_Int32 indexOfPkgSpec = m_sCtxString.lastIndexOf( pkgSpec );
+
+ // if context string ends with "uno_packages"
+ if ( indexOfPkgSpec > -1 && m_sCtxString.match( pkgSpec, indexOfPkgSpec ) )
+ {
+ m_bIsPkgMSP = true;
+ }
+ else
+ {
+ m_bIsPkgMSP = false;
+ }
+ }
+ else // no args
+ {
+ // use either scripting context or maybe zero args?
+ invokeArgs = Sequence< Any >( 0 ); // no arguments
+ }
+ m_sAargs = invokeArgs;
+ // don't create pkg mgr MSP for documents, not supported
+ if ( !m_bIsPkgMSP && !m_xModel.is() )
+ {
+ createPkgProvider();
+ }
+
+ m_bInitialised = true;
+ m_bIsValid = true;
+}
+
+
+void MasterScriptProvider::createPkgProvider()
+{
+ try
+ {
+ Any location;
+ location <<= m_sCtxString + ":uno_packages";
+
+ Reference< provider::XScriptProviderFactory > xFac =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ m_xMSPPkg.set(
+ xFac->createScriptProvider( location ), UNO_SET_THROW );
+
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("scripting.provider", "Exception creating MasterScriptProvider for uno_packages in context "
+ << m_sCtxString );
+ }
+}
+
+
+Reference< provider::XScript >
+MasterScriptProvider::getScript( const OUString& scriptURI )
+{
+ if ( !m_bIsValid )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "MasterScriptProvider not initialised", Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ // need to get the language from the string
+
+ Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) );
+
+ Reference< uri::XUriReference > uriRef = xFac->parse( scriptURI );
+
+ Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY );
+
+ if ( !uriRef.is() || !sfUri.is() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "Incorrect format for Script URI: " + scriptURI,
+ Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ OUString langKey("language");
+ OUString locKey("location");
+
+ if ( !sfUri->hasParameter( langKey ) ||
+ !sfUri->hasParameter( locKey ) ||
+ ( sfUri->getName().isEmpty() ) )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "Incorrect format for Script URI: " + scriptURI,
+ Reference< XInterface >(),
+ scriptURI, "",
+ provider::ScriptFrameworkErrorType::UNKNOWN );
+ }
+
+ OUString language = sfUri->getParameter( langKey );
+ OUString location = sfUri->getParameter( locKey );
+
+ // if script us located in uno pkg
+ sal_Int32 index = -1;
+ OUString pkgTag(":uno_packages");
+ // for languages other than basic, scripts located in uno packages
+ // are merged into the user/share location context.
+ // For other languages the location attribute in script url has the form
+ // location = [user|share]:uno_packages or location :uno_packages/xxxx.uno.pkg
+ // we need to extract the value of location part from the
+ // location attribute of the script, if the script is located in an
+ // uno package then that is the location part up to and including
+ // ":uno_packages", if the script is not in a uno package then the
+ // normal value is used e.g. user or share.
+ // The value extracted will be used to determine if the script is
+ // located in the same location context as this MSP.
+ // For Basic, the language script provider can handle the execution of a
+ // script in any location context
+ if ( ( index = location.indexOf( pkgTag ) ) > -1 )
+ {
+ location = location.copy( 0, index + pkgTag.getLength() );
+ }
+
+ Reference< provider::XScript > xScript;
+
+ // If the script location is in the same location context as this
+ // MSP then delete to the language provider controlled by this MSP
+ // ** Special case is BASIC, all calls to getScript will be handled
+ // by the language script provider in the current location context
+ // even if it's different
+ if ( ( location == "document"
+ && m_xModel.is()
+ )
+ || ( endsWith( m_sCtxString, location ) )
+ || ( language == "Basic" )
+ )
+ {
+ Reference< provider::XScriptProvider > xScriptProvider;
+ OUString serviceName = "com.sun.star.script.provider.ScriptProviderFor" + language;
+ if ( !providerCache() )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ "No LanguageProviders detected",
+ Reference< XInterface >(),
+ sfUri->getName(), language,
+ provider::ScriptFrameworkErrorType::NOTSUPPORTED );
+ }
+
+ try
+ {
+ xScriptProvider.set(
+ providerCache()->getProvider( serviceName ),
+ UNO_SET_THROW );
+ }
+ catch( const Exception& e )
+ {
+ throw provider::ScriptFrameworkErrorException(
+ e.Message, Reference< XInterface >(),
+ sfUri->getName(), language,
+ provider::ScriptFrameworkErrorType::NOTSUPPORTED );
+ }
+
+ xScript=xScriptProvider->getScript( scriptURI );
+ }
+ else
+ {
+ Reference< provider::XScriptProviderFactory > xFac_ =
+ provider::theMasterScriptProviderFactory::get( m_xContext );
+
+ Reference< provider::XScriptProvider > xSP(
+ xFac_->createScriptProvider( Any( location ) ), UNO_SET_THROW );
+ xScript = xSP->getScript( scriptURI );
+ }
+
+ return xScript;
+}
+
+
+ProviderCache*
+MasterScriptProvider::providerCache()
+{
+ if ( !m_pPCache )
+ {
+ std::scoped_lock aGuard( m_mutex );
+ if ( !m_pPCache )
+ {
+ Sequence<OUString> denylist { "com.sun.star.script.provider.ScriptProviderForBasic" };
+
+ if ( !m_bIsPkgMSP )
+ {
+ m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs ) );
+ }
+ else
+ {
+ m_pPCache.reset( new ProviderCache( m_xContext, m_sAargs, denylist ) );
+ }
+ }
+ }
+ return m_pPCache.get();
+}
+
+
+OUString SAL_CALL
+MasterScriptProvider::getName()
+{
+ if ( !m_bIsPkgMSP )
+ {
+ OUString sCtx = getContextString();
+ if ( sCtx.startsWith( "vnd.sun.star.tdoc" ) )
+ {
+ Reference< frame::XModel > xModel = m_xModel;
+ if ( !xModel.is() )
+ {
+ xModel = MiscUtils::tDocUrlToModel( sCtx );
+ }
+
+ m_sNodeName = ::comphelper::DocumentInfo::getDocumentTitle( xModel );
+ }
+ else
+ {
+ m_sNodeName = parseLocationName( getContextString() );
+ }
+ }
+ else
+ {
+ m_sNodeName = "uno_packages";
+ }
+ return m_sNodeName;
+}
+
+
+Sequence< Reference< browse::XBrowseNode > > SAL_CALL
+MasterScriptProvider::getChildNodes()
+{
+ Sequence< Reference< provider::XScriptProvider > > providers = providerCache()->getAllProviders();
+
+ sal_Int32 size = providers.getLength();
+ bool hasPkgs = m_xMSPPkg.is();
+ if ( hasPkgs )
+ {
+ size++;
+ }
+ Sequence< Reference< browse::XBrowseNode > > children( size );
+ auto childrenRange = asNonConstRange(children);
+ sal_Int32 provIndex = 0;
+ for ( ; provIndex < providers.getLength(); provIndex++ )
+ {
+ childrenRange[ provIndex ].set( providers[ provIndex ], UNO_QUERY );
+ }
+
+ if ( hasPkgs )
+ {
+ childrenRange[ provIndex ].set( m_xMSPPkg, UNO_QUERY );
+
+ }
+
+ return children;
+}
+
+
+sal_Bool SAL_CALL
+MasterScriptProvider::hasChildNodes()
+{
+ return true;
+}
+
+
+sal_Int16 SAL_CALL
+MasterScriptProvider::getType()
+{
+ return browse::BrowseNodeTypes::CONTAINER;
+}
+
+
+OUString
+MasterScriptProvider::parseLocationName( const OUString& location )
+{
+ // strip out the last leaf of location name
+ // e.g. file://dir1/dir2/Blah.sxw - > Blah.sxw
+ OUString temp = location;
+ INetURLObject aURLObj( temp );
+ if ( !aURLObj.HasError() )
+ temp = aURLObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ return temp;
+}
+
+namespace
+{
+template <typename Proc> bool FindProviderAndApply(ProviderCache& rCache, Proc p)
+{
+ auto pass = [&rCache, &p]() -> bool
+ {
+ bool bResult = false;
+ const Sequence<Reference<provider::XScriptProvider>> aAllProviders = rCache.getAllProviders();
+ for (const auto& rProv : aAllProviders)
+ {
+ Reference<container::XNameContainer> xCont(rProv, UNO_QUERY);
+ if (!xCont.is())
+ {
+ continue;
+ }
+ try
+ {
+ bResult = p(xCont);
+ if (bResult)
+ break;
+ }
+ catch (const Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("scripting.provider", "ignoring");
+ }
+ }
+ return bResult;
+ };
+ bool bSuccess = false;
+ // 1. Try to perform the operation without trying to enable JVM (if disabled)
+ // This allows us to avoid useless user interaction in case when other provider
+ // (not JVM) actually handles the operation.
+ {
+ css::uno::ContextLayer layer(comphelper::NoEnableJavaInteractionContext());
+ bSuccess = pass();
+ }
+ // 2. Now retry asking to enable JVM in case we didn't succeed first time
+ if (!bSuccess)
+ {
+ bSuccess = pass();
+ }
+ return bSuccess;
+}
+} // namespace
+
+// Register Package
+void SAL_CALL
+MasterScriptProvider::insertByName( const OUString& aName, const Any& aElement )
+{
+ if ( !m_bIsPkgMSP )
+ {
+ if ( !m_xMSPPkg.is() )
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ xCont->insertByName( aName, aElement );
+ }
+ else
+ {
+ Reference< deployment::XPackage > xPkg( aElement, UNO_QUERY );
+ if ( !xPkg.is() )
+ {
+ throw lang::IllegalArgumentException( "Couldn't convert to XPackage",
+ Reference < XInterface > (), 2 );
+ }
+ if ( aName.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for library package parse the language, for the moment will try
+ // to get each provider to process the new Package, the first one the succeeds
+ // will terminate processing
+ const bool bSuccess = FindProviderAndApply(
+ *providerCache(), [&aName, &aElement](Reference<container::XNameContainer>& xCont) {
+ xCont->insertByName(aName, aElement);
+ return true;
+ });
+ if (!bSuccess)
+ {
+ // No script providers could process the package
+ throw lang::IllegalArgumentException( "Failed to register package for " + aName,
+ Reference < XInterface > (), 2 );
+ }
+ }
+}
+
+
+// Revoke Package
+void SAL_CALL
+MasterScriptProvider::removeByName( const OUString& Name )
+{
+ if ( !m_bIsPkgMSP )
+ {
+ if ( !m_xMSPPkg.is() )
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ xCont->removeByName( Name );
+ }
+ else
+ {
+ if ( Name.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for Script library package url parse the language,
+ // for the moment will just try to get each provider to process remove/revoke
+ // request, the first one the succeeds will terminate processing
+ const bool bSuccess = FindProviderAndApply(
+ *providerCache(), [&Name](Reference<container::XNameContainer>& xCont) {
+ xCont->removeByName(Name);
+ return true;
+ });
+ if (!bSuccess)
+ {
+ // No script providers could process the package
+ throw lang::IllegalArgumentException( "Failed to revoke package for " + Name,
+ Reference < XInterface > (), 1 );
+ }
+
+ }
+}
+
+
+void SAL_CALL
+MasterScriptProvider::replaceByName( const OUString& /*aName*/, const Any& /*aElement*/ )
+{
+ // TODO needs implementing
+ throw RuntimeException( "replaceByName not implemented!!!!" );
+}
+
+Any SAL_CALL
+MasterScriptProvider::getByName( const OUString& /*aName*/ )
+{
+ // TODO needs to be implemented
+ throw RuntimeException( "getByName not implemented!!!!" );
+}
+
+sal_Bool SAL_CALL
+MasterScriptProvider::hasByName( const OUString& aName )
+{
+ bool result = false;
+ if ( !m_bIsPkgMSP )
+ {
+ if ( m_xMSPPkg.is() )
+ {
+ Reference< container::XNameContainer > xCont( m_xMSPPkg, UNO_QUERY_THROW );
+ result = xCont->hasByName( aName );
+ }
+ // If this is a document provider then we shouldn't
+ // have a PackageProvider
+ else if (!m_xModel.is())
+ {
+ throw RuntimeException( "PackageMasterScriptProvider is unitialised" );
+ }
+
+ }
+ else
+ {
+ if ( aName.isEmpty() )
+ {
+ throw lang::IllegalArgumentException( "Name not set!!",
+ Reference < XInterface > (), 1 );
+ }
+ // TODO for Script library package url parse the language,
+ // for the moment will just try to get each provider to see if the
+ // package exists in any provider, first one that succeed will
+ // terminate the loop
+ result = FindProviderAndApply(
+ *providerCache(), [&aName](Reference<container::XNameContainer>& xCont) {
+ return xCont->hasByName(aName);
+ });
+ }
+ return result;
+}
+
+
+Sequence< OUString > SAL_CALL
+MasterScriptProvider::getElementNames( )
+{
+ // TODO needs implementing
+ throw RuntimeException( "getElementNames not implemented!!!!" );
+}
+
+Type SAL_CALL
+MasterScriptProvider::getElementType( )
+{
+ // TODO needs implementing
+ Type t;
+ return t;
+}
+
+sal_Bool SAL_CALL MasterScriptProvider::hasElements( )
+{
+ // TODO needs implementing
+ throw RuntimeException( "hasElements not implemented!!!!" );
+}
+
+
+OUString SAL_CALL MasterScriptProvider::getImplementationName( )
+{
+ return "com.sun.star.script.provider.MasterScriptProvider";
+}
+
+sal_Bool SAL_CALL MasterScriptProvider::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+
+Sequence< OUString > SAL_CALL MasterScriptProvider::getSupportedServiceNames( )
+{
+ return {
+ "com.sun.star.script.provider.MasterScriptProvider",
+ "com.sun.star.script.browse.BrowseNode",
+ "com.sun.star.script.provider.ScriptProvider" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_MasterScriptProvider_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new MasterScriptProvider(context));
+}
+
+} // namespace func_provider
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProvider.hxx b/scripting/source/provider/MasterScriptProvider.hxx
new file mode 100644
index 0000000000..0e6c40f5f0
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProvider.hxx
@@ -0,0 +1,131 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+#include <com/sun/star/script/browse/XBrowseNode.hpp>
+
+#include "ProviderCache.hxx"
+#include <memory>
+#include <mutex>
+
+namespace func_provider
+{
+
+ typedef ::cppu::WeakImplHelper<
+ css::script::provider::XScriptProvider,
+ css::script::browse::XBrowseNode, css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::container::XNameContainer > t_helper;
+
+class MasterScriptProvider :
+ public t_helper
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit MasterScriptProvider(
+ const css::uno::Reference< css::uno::XComponentContext >
+ & xContext );
+ virtual ~MasterScriptProvider() override;
+
+ // XServiceInfo implementation
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // XBrowseNode implementation
+ virtual OUString SAL_CALL getName() override;
+ virtual css::uno::Sequence< css::uno::Reference< css::script::browse::XBrowseNode > > SAL_CALL getChildNodes() override;
+ virtual sal_Bool SAL_CALL hasChildNodes() override;
+ virtual sal_Int16 SAL_CALL getType() override;
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XScriptProvider implementation
+ virtual css::uno::Reference < css::script::provider::XScript > SAL_CALL
+ getScript( const OUString& scriptURI ) override;
+
+ /**
+ * XInitialise implementation
+ *
+ * @param args expected to contain a single OUString
+ * containing the URI
+ */
+ virtual void SAL_CALL initialize( const css::uno::Sequence < css::uno::Any > & args ) override;
+
+ // returns context string for this provider, eg
+ const OUString& getContextString() const { return m_sCtxString; }
+
+private:
+ static OUString parseLocationName( const OUString& location );
+ void createPkgProvider();
+
+ ProviderCache* providerCache();
+ /* to obtain other services if needed */
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_xMgr;
+ css::uno::Reference< css::frame::XModel > m_xModel;
+ css::uno::Reference< css::document::XScriptInvocationContext > m_xInvocationContext;
+ css::uno::Sequence< css::uno::Any > m_sAargs;
+ OUString m_sNodeName;
+
+ // This component supports XInitialization, it can be created
+ // using createInstanceXXX() or createInstanceWithArgumentsXXX using
+ // the service Manager.
+ // Need to detect proper initialisation and validity
+ // for the object, so m_bIsValid indicates that the object is valid is set in ctor
+ // in case of createInstanceWithArgumentsXXX() called m_bIsValid is set to reset
+ // and then set to true when initialisation is complete
+ bool m_bIsValid;
+ // m_bInitialised ensure initialisation only takes place once.
+ bool m_bInitialised;
+ bool m_bIsPkgMSP;
+ css::uno::Reference< css::script::provider::XScriptProvider > m_xMSPPkg;
+ std::unique_ptr<ProviderCache> m_pPCache;
+ std::mutex m_mutex;
+ OUString m_sCtxString;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProviderFactory.cxx b/scripting/source/provider/MasterScriptProviderFactory.cxx
new file mode 100644
index 0000000000..acdb8f8da0
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProviderFactory.cxx
@@ -0,0 +1,85 @@
+/* -*- 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 <cppuhelper/supportsservice.hxx>
+
+#include "MasterScriptProviderFactory.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::script;
+
+namespace func_provider
+{
+
+MasterScriptProviderFactory::MasterScriptProviderFactory(
+ Reference< XComponentContext > const & xComponentContext )
+ : m_xComponentContext( xComponentContext )
+{
+}
+
+MasterScriptProviderFactory::~MasterScriptProviderFactory()
+{
+}
+
+Reference< provider::XScriptProvider > SAL_CALL
+MasterScriptProviderFactory::createScriptProvider( const Any& context )
+{
+ Reference< provider::XScriptProvider > xMsp( getActiveMSPList() ->getMSPFromAnyContext( context ), UNO_SET_THROW );
+ return xMsp;
+}
+
+const rtl::Reference< ActiveMSPList > &
+MasterScriptProviderFactory::getActiveMSPList() const
+{
+ if ( !m_MSPList.is() )
+ {
+ ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() );
+ if ( !m_MSPList.is() )
+ m_MSPList = new ActiveMSPList( m_xComponentContext );
+ }
+ return m_MSPList;
+}
+
+OUString SAL_CALL MasterScriptProviderFactory::getImplementationName()
+{
+ return "com.sun.star.script.provider.MasterScriptProviderFactory";
+}
+
+Sequence< OUString > SAL_CALL MasterScriptProviderFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.provider.MasterScriptProviderFactory" };
+}
+
+sal_Bool MasterScriptProviderFactory::supportsService(
+ OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+} // namespace func_provider
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_MasterScriptProviderFactory_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new func_provider::MasterScriptProviderFactory(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/MasterScriptProviderFactory.hxx b/scripting/source/provider/MasterScriptProviderFactory.hxx
new file mode 100644
index 0000000000..9fbc8705db
--- /dev/null
+++ b/scripting/source/provider/MasterScriptProviderFactory.hxx
@@ -0,0 +1,74 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <com/sun/star/script/provider/XScriptProviderFactory.hpp>
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+
+#include "ActiveMSPList.hxx"
+
+namespace func_provider
+{
+
+class MasterScriptProviderFactory :
+ public ::cppu::WeakImplHelper <
+ css::script::provider::XScriptProviderFactory,
+ css::lang::XServiceInfo >
+{
+private:
+
+ mutable rtl::Reference< ActiveMSPList > m_MSPList;
+
+ const css::uno::Reference< css::uno::XComponentContext > m_xComponentContext;
+
+ const rtl::Reference< ActiveMSPList > & getActiveMSPList() const;
+
+protected:
+ virtual ~MasterScriptProviderFactory() override;
+
+public:
+ explicit MasterScriptProviderFactory(
+ css::uno::Reference< css::uno::XComponentContext > const & xComponentContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( OUString const & serviceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XScriptProviderFactory
+ virtual css::uno::Reference< css::script::provider::XScriptProvider >
+ SAL_CALL createScriptProvider( const css::uno::Any& context ) override;
+};
+
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ProviderCache.cxx b/scripting/source/provider/ProviderCache.cxx
new file mode 100644
index 0000000000..7b240fe590
--- /dev/null
+++ b/scripting/source/provider/ProviderCache.cxx
@@ -0,0 +1,203 @@
+/* -*- 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 <comphelper/sequence.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include "ProviderCache.hxx"
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::script;
+
+namespace func_provider
+{
+
+ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext ) : m_Sctx( scriptContext ), m_xContext( xContext )
+{
+ // initialise m_hProviderDetailsCache with details of ScriptProviders
+ // will use createContentEnumeration
+
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
+ populateCache();
+}
+
+
+ProviderCache::ProviderCache( const Reference< XComponentContext >& xContext, const Sequence< Any >& scriptContext, const Sequence< OUString >& denyList ) : m_sDenyList( denyList ), m_Sctx( scriptContext ), m_xContext( xContext )
+
+{
+ // initialise m_hProviderDetailsCache with details of ScriptProviders
+ // will use createContentEnumeration
+
+ m_xMgr = m_xContext->getServiceManager();
+ ENSURE_OR_THROW( m_xMgr.is(), "ProviderCache::ProviderCache() failed to obtain ServiceManager" );
+ populateCache();
+}
+
+ProviderCache::~ProviderCache()
+{
+}
+
+Reference< provider::XScriptProvider >
+ProviderCache::getProvider( const OUString& providerName )
+{
+ std::scoped_lock aGuard( m_mutex );
+ Reference< provider::XScriptProvider > provider;
+ ProviderDetails_hash::iterator h_it = m_hProviderDetailsCache.find( providerName );
+ if ( h_it != m_hProviderDetailsCache.end() )
+ {
+ if ( h_it->second.provider.is() )
+ {
+ provider = h_it->second.provider;
+ }
+ else
+ {
+ // need to create provider and insert into hash
+ provider = createProvider( h_it->second );
+ }
+ }
+ return provider;
+}
+
+Sequence < Reference< provider::XScriptProvider > >
+ProviderCache::getAllProviders()
+{
+ // need to create providers that haven't been created already
+ // so check what providers exist and what ones don't
+
+ std::scoped_lock aGuard( m_mutex );
+ Sequence < Reference< provider::XScriptProvider > > providers ( m_hProviderDetailsCache.size() );
+ // should assert if size !> 0
+ if ( !m_hProviderDetailsCache.empty() )
+ {
+ auto pproviders = providers.getArray();
+ sal_Int32 providerIndex = 0;
+ for (auto& rDetail : m_hProviderDetailsCache)
+ {
+ Reference<provider::XScriptProvider> xScriptProvider = rDetail.second.provider;
+ if ( xScriptProvider.is() )
+ {
+ pproviders[ providerIndex++ ] = xScriptProvider;
+ }
+ else
+ {
+ // create provider
+ try
+ {
+ xScriptProvider = createProvider(rDetail.second);
+ pproviders[ providerIndex++ ] = xScriptProvider;
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("scripting");
+ }
+ }
+ }
+
+ if (providerIndex < providers.getLength())
+ {
+ providers.realloc( providerIndex );
+ }
+
+ }
+ else
+ {
+ SAL_WARN("scripting", "no available providers, something very wrong!!!");
+ }
+ return providers;
+}
+
+void
+ProviderCache::populateCache()
+{
+ // wrong name in services.rdb
+ OUString serviceName;
+ std::scoped_lock aGuard( m_mutex );
+ try
+ {
+ Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMgr, UNO_QUERY_THROW );
+ Reference< container::XEnumeration > xEnum = xEnumAccess->createContentEnumeration ( "com.sun.star.script.provider.LanguageScriptProvider" );
+
+ while ( xEnum->hasMoreElements() )
+ {
+
+ Reference< lang::XSingleComponentFactory > factory( xEnum->nextElement(), UNO_QUERY_THROW );
+ Reference< lang::XServiceInfo > xServiceInfo( factory, UNO_QUERY_THROW );
+
+ const Sequence< OUString > serviceNames = xServiceInfo->getSupportedServiceNames();
+
+ if ( serviceNames.hasElements() )
+ {
+ auto pName = std::find_if(serviceNames.begin(), serviceNames.end(),
+ [this](const OUString& rName) {
+ return rName.startsWith("com.sun.star.script.provider.ScriptProviderFor")
+ && !isInDenyList(rName);
+ });
+ if (pName != serviceNames.end())
+ {
+ serviceName = *pName;
+ ProviderDetails details;
+ details.factory = factory;
+ m_hProviderDetailsCache[ serviceName ] = details;
+ }
+ }
+ }
+ }
+ catch ( const Exception &e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "ProviderCache::populateCache: couldn't obtain XSingleComponentFactory for " + serviceName
+ + " " + e.Message,
+ nullptr, anyEx );
+ }
+}
+
+Reference< provider::XScriptProvider >
+ProviderCache::createProvider( ProviderDetails& details )
+{
+ try
+ {
+ details.provider.set(
+ details.factory->createInstanceWithArgumentsAndContext( m_Sctx, m_xContext ), UNO_QUERY_THROW );
+ }
+ catch ( const Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "ProviderCache::createProvider() Error creating provider from factory. " + e.Message,
+ nullptr, anyEx );
+ }
+
+ return details.provider;
+}
+
+bool
+ProviderCache::isInDenyList( const OUString& serviceName ) const
+{
+ return comphelper::findValue(m_sDenyList, serviceName) != -1;
+}
+} //end namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/ProviderCache.hxx b/scripting/source/provider/ProviderCache.hxx
new file mode 100644
index 0000000000..b565d1d082
--- /dev/null
+++ b/scripting/source/provider/ProviderCache.hxx
@@ -0,0 +1,80 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <com/sun/star/script/provider/XScriptProvider.hpp>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace func_provider
+{
+
+//Typedefs
+
+
+struct ProviderDetails
+{
+ //css::uno::Reference< css::lang::XSingleServiceFactory > factory;
+ css::uno::Reference< css::lang::XSingleComponentFactory > factory;
+ css::uno::Reference< css::script::provider::XScriptProvider > provider;
+};
+typedef std::unordered_map < OUString, ProviderDetails > ProviderDetails_hash;
+
+
+class ProviderCache
+{
+
+public:
+ /// @throws css::uno::RuntimeException
+ ProviderCache( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Sequence< css::uno::Any >& scriptContext );
+ /// @throws css::uno::RuntimeException
+ ProviderCache( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Sequence< css::uno::Any >& scriptContext,
+ const css::uno::Sequence< OUString >& denyList );
+ ~ProviderCache();
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ getProvider( const OUString& providerName );
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence < css::uno::Reference< css::script::provider::XScriptProvider > >
+ getAllProviders();
+private:
+ /// @throws css::uno::RuntimeException
+ void populateCache();
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::script::provider::XScriptProvider >
+ createProvider( ProviderDetails& details );
+ bool isInDenyList( const OUString& serviceName ) const;
+ css::uno::Sequence< OUString > m_sDenyList;
+ ProviderDetails_hash m_hProviderDetailsCache;
+ std::mutex m_mutex;
+ css::uno::Sequence< css::uno::Any > m_Sctx;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::lang::XMultiComponentFactory > m_xMgr;
+
+
+};
+} // func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/URIHelper.cxx b/scripting/source/provider/URIHelper.cxx
new file mode 100644
index 0000000000..4b122da8b1
--- /dev/null
+++ b/scripting/source/provider/URIHelper.cxx
@@ -0,0 +1,256 @@
+/* -*- 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_folders.h>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/diagnose.h>
+#include "URIHelper.hxx"
+
+namespace func_provider
+{
+
+namespace uno = ::com::sun::star::uno;
+namespace ucb = ::com::sun::star::ucb;
+namespace lang = ::com::sun::star::lang;
+namespace uri = ::com::sun::star::uri;
+
+constexpr OUString SHARE = u"share"_ustr;
+
+constexpr OUStringLiteral SHARE_UNO_PACKAGES_URI =
+ u"vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE";
+
+constexpr OUString USER = u"user"_ustr;
+constexpr OUString USER_URI =
+ u"vnd.sun.star.expand:${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}"_ustr;
+
+
+
+ScriptingFrameworkURIHelper::ScriptingFrameworkURIHelper(
+ const uno::Reference< uno::XComponentContext >& xContext)
+{
+ try
+ {
+ m_xSimpleFileAccess = ucb::SimpleFileAccess::create(xContext);
+ }
+ catch (uno::Exception&)
+ {
+ OSL_FAIL("Scripting Framework error initialising XSimpleFileAccess");
+ }
+
+ try
+ {
+ m_xUriReferenceFactory = uri::UriReferenceFactory::create( xContext );
+ }
+ catch (uno::Exception&)
+ {
+ OSL_FAIL("Scripting Framework error initialising XUriReferenceFactory");
+ }
+}
+
+ScriptingFrameworkURIHelper::~ScriptingFrameworkURIHelper()
+{
+ // currently does nothing
+}
+
+void SAL_CALL
+ScriptingFrameworkURIHelper::initialize(
+ const uno::Sequence < uno::Any >& args )
+{
+ if ( args.getLength() != 2 ||
+ args[0].getValueType() != ::cppu::UnoType<OUString>::get() ||
+ args[1].getValueType() != ::cppu::UnoType<OUString>::get() )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper got invalid argument list" );
+ }
+
+ if ( !(args[0] >>= m_sLanguage) || !(args[1] >>= m_sLocation) )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper error parsing args" );
+ }
+
+ SCRIPTS_PART = "/Scripts/" + m_sLanguage.toAsciiLowerCase();
+
+ if ( !initBaseURI() )
+ {
+ throw uno::RuntimeException( "ScriptingFrameworkURIHelper cannot find script directory" );
+ }
+}
+
+bool
+ScriptingFrameworkURIHelper::initBaseURI()
+{
+ OUString uri, test;
+ bool bAppendScriptsPart = false;
+
+ if ( m_sLocation == USER )
+ {
+ test = USER;
+ uri = USER_URI;
+ bAppendScriptsPart = true;
+ }
+ else if ( m_sLocation == "user:uno_packages" )
+ {
+ test = "uno_packages";
+ uri = USER_URI + "/user/uno_packages/cache";
+ }
+ else if (m_sLocation == SHARE)
+ {
+ test = SHARE;
+ uri = "vnd.sun.star.expand:$BRAND_BASE_DIR";
+ bAppendScriptsPart = true;
+ }
+ else if (m_sLocation == "share:uno_packages")
+ {
+ test = "uno_packages";
+ uri = SHARE_UNO_PACKAGES_URI;
+ }
+ else if (m_sLocation.startsWith("vnd.sun.star.tdoc"))
+ {
+ m_sBaseURI = m_sLocation + SCRIPTS_PART;
+ m_sLocation = "document";
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ if ( !m_xSimpleFileAccess->exists( uri ) ||
+ !m_xSimpleFileAccess->isFolder( uri ) )
+ {
+ return false;
+ }
+
+ const uno::Sequence< OUString > children =
+ m_xSimpleFileAccess->getFolderContents( uri, true );
+
+ auto pChild = std::find_if(children.begin(), children.end(), [&test](const OUString& child) {
+ sal_Int32 idx = child.lastIndexOf(test);
+ return idx != -1 && (idx + test.getLength()) == child.getLength();
+ });
+ if (pChild != children.end())
+ {
+ if ( bAppendScriptsPart )
+ {
+ m_sBaseURI = *pChild + SCRIPTS_PART;
+ }
+ else
+ {
+ m_sBaseURI = *pChild;
+ }
+ return true;
+ }
+ return false;
+}
+
+OUString
+ScriptingFrameworkURIHelper::getLanguagePart(std::u16string_view rStorageURI)
+{
+ OUString result;
+
+ size_t idx = rStorageURI.find(m_sBaseURI);
+ sal_Int32 len = m_sBaseURI.getLength() + 1;
+
+ if ( idx != std::u16string_view::npos )
+ {
+ result = rStorageURI.substr(idx + len);
+ result = result.replace('/', '|');
+ }
+ return result;
+}
+
+OUString
+ScriptingFrameworkURIHelper::getLanguagePath(const OUString& rLanguagePart)
+{
+ OUString result = rLanguagePart.replace('|', '/');
+ return result;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getScriptURI(const OUString& rStorageURI)
+{
+ return
+ "vnd.sun.star.script:" +
+ getLanguagePart(rStorageURI) +
+ "?language=" +
+ m_sLanguage +
+ "&location=" +
+ m_sLocation;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getStorageURI(const OUString& rScriptURI)
+{
+ OUString sLanguagePart;
+ try
+ {
+ uno::Reference < uri::XVndSunStarScriptUrl > xURI(
+ m_xUriReferenceFactory->parse( rScriptURI ), uno::UNO_QUERY_THROW );
+ sLanguagePart = xURI->getName();
+ }
+ catch ( uno::Exception& )
+ {
+ throw lang::IllegalArgumentException(
+ "Script URI not valid",
+ uno::Reference< uno::XInterface >(), 1 );
+ }
+
+ return m_sBaseURI + "/" + getLanguagePath(sLanguagePart);
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getRootStorageURI()
+{
+ return m_sBaseURI;
+}
+
+OUString SAL_CALL
+ScriptingFrameworkURIHelper::getImplementationName()
+{
+ return
+ "com.sun.star.script.provider.ScriptURIHelper";
+}
+
+sal_Bool SAL_CALL
+ScriptingFrameworkURIHelper::supportsService( const OUString& serviceName )
+{
+ return cppu::supportsService( this, serviceName );
+}
+
+uno::Sequence< OUString > SAL_CALL
+ScriptingFrameworkURIHelper::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.provider.ScriptURIHelper" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+scripting_ScriptingFrameworkURIHelper_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ScriptingFrameworkURIHelper(context));
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scripting/source/provider/URIHelper.hxx b/scripting/source/provider/URIHelper.hxx
new file mode 100644
index 0000000000..9d200a1a37
--- /dev/null
+++ b/scripting/source/provider/URIHelper.hxx
@@ -0,0 +1,87 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/script/provider/XScriptURIHelper.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace func_provider
+{
+
+class ScriptingFrameworkURIHelper :
+ public ::cppu::WeakImplHelper<
+ css::script::provider::XScriptURIHelper,
+ css::lang::XServiceInfo,
+ css::lang::XInitialization >
+{
+private:
+
+ css::uno::Reference< css::ucb::XSimpleFileAccess3 > m_xSimpleFileAccess;
+ css::uno::Reference<css::uri::XUriReferenceFactory> m_xUriReferenceFactory;
+
+ OUString m_sLanguage;
+ OUString m_sLocation;
+ OUString m_sBaseURI;
+
+ OUString SCRIPTS_PART;
+
+ bool initBaseURI();
+ OUString getLanguagePart(std::u16string_view rStorageURI);
+ static OUString getLanguagePath(const OUString& rLanguagePart);
+
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScriptingFrameworkURIHelper(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+ virtual ~ScriptingFrameworkURIHelper() override;
+
+ virtual void SAL_CALL
+ initialize( const css::uno::Sequence < css::uno::Any > & args ) override;
+
+ virtual OUString SAL_CALL
+ getRootStorageURI() override;
+
+ virtual OUString SAL_CALL
+ getScriptURI( const OUString& rStorageURI ) override;
+
+ virtual OUString SAL_CALL
+ getStorageURI( const OUString& rScriptURI ) override;
+
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+};
+
+} // namespace func_provider
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */