diff options
Diffstat (limited to 'scripting/source/provider')
-rw-r--r-- | scripting/source/provider/ActiveMSPList.cxx | 295 | ||||
-rw-r--r-- | scripting/source/provider/ActiveMSPList.hxx | 94 | ||||
-rw-r--r-- | scripting/source/provider/BrowseNodeFactoryImpl.cxx | 650 | ||||
-rw-r--r-- | scripting/source/provider/BrowseNodeFactoryImpl.hxx | 70 | ||||
-rw-r--r-- | scripting/source/provider/MasterScriptProvider.cxx | 676 | ||||
-rw-r--r-- | scripting/source/provider/MasterScriptProvider.hxx | 131 | ||||
-rw-r--r-- | scripting/source/provider/MasterScriptProviderFactory.cxx | 85 | ||||
-rw-r--r-- | scripting/source/provider/MasterScriptProviderFactory.hxx | 74 | ||||
-rw-r--r-- | scripting/source/provider/ProviderCache.cxx | 203 | ||||
-rw-r--r-- | scripting/source/provider/ProviderCache.hxx | 80 | ||||
-rw-r--r-- | scripting/source/provider/URIHelper.cxx | 256 | ||||
-rw-r--r-- | scripting/source/provider/URIHelper.hxx | 87 |
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: */ |