diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /stoc/source/invocation | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | stoc/source/invocation/invocation.component | 26 | ||||
-rw-r--r-- | stoc/source/invocation/invocation.cxx | 1097 | ||||
-rw-r--r-- | stoc/source/invocation_adapterfactory/iafactory.cxx | 882 | ||||
-rw-r--r-- | stoc/source/invocation_adapterfactory/invocadapt.component | 26 |
4 files changed, 2031 insertions, 0 deletions
diff --git a/stoc/source/invocation/invocation.component b/stoc/source/invocation/invocation.component new file mode 100644 index 000000000..b5027a4d6 --- /dev/null +++ b/stoc/source/invocation/invocation.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.stoc.Invocation" + constructor="stoc_InvocationService_get_implementation"> + <service name="com.sun.star.script.Invocation"/> + </implementation> +</component> diff --git a/stoc/source/invocation/invocation.cxx b/stoc/source/invocation/invocation.cxx new file mode 100644 index 000000000..5463c059e --- /dev/null +++ b/stoc/source/invocation/invocation.cxx @@ -0,0 +1,1097 @@ +/* -*- 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 <cppuhelper/queryinterface.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/script/XInvocation2.hpp> +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/beans/XExactName.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/beans/theIntrospection.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/MethodConcept.hpp> +#include <com/sun/star/beans/PropertyConcept.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> + +#include <memory> +#include <vector> + +using namespace css::uno; +using namespace css::lang; +using namespace css::script; +using namespace css::reflection; +using namespace css::beans; +using namespace css::container; +using namespace cppu; +using namespace osl; + +namespace stoc_inv +{ + + +// TODO: Implement centrally +static Reference<XIdlClass> TypeToIdlClass( const Type& rType, const Reference< XIdlReflection > & xRefl ) +{ + return xRefl->forName( rType.getTypeName() ); +} + +namespace { + +class Invocation_Impl + : public OWeakObject + , public XInvocation2 + , public XNameContainer + , public XIndexContainer + , public XEnumerationAccess + , public XExactName + , public XMaterialHolder + , public XTypeProvider +{ +public: + Invocation_Impl( const Any & rAdapted, const Reference<XTypeConverter> &, + const Reference<XIntrospection> &, + const Reference<XIdlReflection> &, + bool bFromOLE ); + + // XInterface + virtual Any SAL_CALL queryInterface( const Type & aType) override; + virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); } + virtual void SAL_CALL release() noexcept override { OWeakObject::release(); } + + + // XTypeProvider + virtual Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // XMaterialHolder + virtual Any SAL_CALL getMaterial() override; + + // XInvocation + virtual Reference<XIntrospectionAccess> SAL_CALL getIntrospection() override; + virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override; + virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override; + virtual Any SAL_CALL getValue(const OUString& PropertyName) override; + virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override; + virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override; + + // XInvocation2 + virtual Sequence< OUString > SAL_CALL getMemberNames( ) override; + virtual Sequence< InvocationInfo > SAL_CALL getInfo( ) override; + virtual InvocationInfo SAL_CALL getInfoForName( const OUString& aName, sal_Bool bExact ) override; + + // All Access and Container methods are not thread safe + // XElementAccess + virtual Type SAL_CALL getElementType() override + { return _xElementAccess->getElementType(); } + + virtual sal_Bool SAL_CALL hasElements() override + { return _xElementAccess->hasElements(); } + + // XNameContainer + virtual void SAL_CALL insertByName( const OUString& Name, const Any& Element ) override + { _xNameContainer->insertByName( Name, Element ); } + + virtual void SAL_CALL removeByName( const OUString& Name ) override + { _xNameContainer->removeByName( Name ); } + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& Name, const Any& Element ) override + { _xNameReplace->replaceByName( Name, Element ); } + + // XNameAccess + virtual Any SAL_CALL getByName( const OUString& Name ) override + { return _xNameAccess->getByName( Name ); } + + virtual Sequence<OUString> SAL_CALL getElementNames() override + { return _xNameAccess->getElementNames(); } + + virtual sal_Bool SAL_CALL hasByName( const OUString& Name ) override + { return _xNameAccess->hasByName( Name ); } + + // XIndexContainer + virtual void SAL_CALL insertByIndex( sal_Int32 Index, const Any& Element ) override + { _xIndexContainer->insertByIndex( Index, Element ); } + + virtual void SAL_CALL removeByIndex( sal_Int32 Index ) override + { _xIndexContainer->removeByIndex( Index ); } + + // XIndexReplace + virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const Any& Element ) override + { _xIndexReplace->replaceByIndex( Index, Element ); } + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() override + { return _xIndexAccess->getCount(); } + + virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override + { return _xIndexAccess->getByIndex( Index ); } + + // XEnumerationAccess + virtual Reference<XEnumeration> SAL_CALL createEnumeration() override + { return _xEnumerationAccess->createEnumeration(); } + + // XExactName + virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override; + + +private: + void setMaterial( const Any& rMaterial ); + + void getInfoSequenceImpl( Sequence< OUString >* pStringSeq, Sequence< InvocationInfo >* pInfoSeq ); + void fillInfoForNameAccess( InvocationInfo& rInfo, const OUString& aName ); + static void fillInfoForProperty( InvocationInfo& rInfo, const Property& rProp ); + static void fillInfoForMethod( InvocationInfo& rInfo, const Reference< XIdlMethod >& xMethod ); + + Reference<XTypeConverter> xTypeConverter; + Reference<XIntrospection> xIntrospection; + Reference<XIdlReflection> xCoreReflection; + + Any _aMaterial; + // _xDirect and (_xIntrospectionAccess, xPropertySet) are exclusive + Reference<XInvocation> _xDirect; + Reference<XInvocation2> _xDirect2; + Reference<XPropertySet> _xPropertySet; + Reference<XIntrospectionAccess> _xIntrospectionAccess; + + // supplied Interfaces + Reference<XNameContainer> _xNameContainer; + Reference<XNameReplace> _xNameReplace; + Reference<XNameAccess> _xNameAccess; + Reference<XIndexContainer> _xIndexContainer; + Reference<XIndexReplace> _xIndexReplace; + Reference<XIndexAccess> _xIndexAccess; + Reference<XEnumerationAccess> _xEnumerationAccess; + Reference<XElementAccess> _xElementAccess; + + + Reference<XExactName> _xENDirect, _xENIntrospection; + + bool mbFromOLE; +}; + +} + +Invocation_Impl::Invocation_Impl +( + const Any & rAdapted, + const Reference<XTypeConverter> & rTC, + const Reference<XIntrospection> & rI, + const Reference<XIdlReflection> & rCR, + bool bFromOLE +) + : xTypeConverter( rTC ) + , xIntrospection( rI ) + , xCoreReflection( rCR ) + , mbFromOLE( bFromOLE ) +{ + setMaterial( rAdapted ); +} + +//### INTERFACE IMPLEMENTATIONS #################################################################### + + +Any SAL_CALL Invocation_Impl::queryInterface( const Type & aType ) +{ + // PropertySet implementation + Any a = ::cppu::queryInterface( aType, + static_cast< XInvocation* >(this), + static_cast< XMaterialHolder* >(this), + static_cast< XTypeProvider * >(this) ); + if( a.hasValue() ) + { + return a; + } + + if( aType == cppu::UnoType<XExactName>::get()) + { + // Invocation does not support XExactName, if direct object supports + // XInvocation, but not XExactName. Except when called from OLE Automation. + if (mbFromOLE || + (_xDirect.is() && _xENDirect.is()) || + (!_xDirect.is() && _xENIntrospection.is())) + { + return Any( Reference< XExactName >( static_cast< XExactName* >(this) ) ); + } + } + else if ( aType == cppu::UnoType<XNameContainer>::get()) + { + if( _xNameContainer.is() ) + return Any( Reference< XNameContainer >( static_cast< XNameContainer* >(this) ) ); + } + else if ( aType == cppu::UnoType<XNameReplace>::get()) + { + if( _xNameReplace.is() ) + return Any( Reference< XNameReplace >( static_cast< XNameReplace* >(this) ) ); + } + else if ( aType == cppu::UnoType<XNameAccess>::get()) + { + if( _xNameAccess.is() ) + return Any( Reference< XNameAccess >( static_cast< XNameAccess* >(this) ) ); + } + else if ( aType == cppu::UnoType<XIndexContainer>::get()) + { + if (_xIndexContainer.is()) + return Any( Reference< XIndexContainer >( static_cast< XIndexContainer* >(this) ) ); + } + else if ( aType == cppu::UnoType<XIndexReplace>::get()) + { + if (_xIndexReplace.is()) + return Any( Reference< XIndexReplace >( static_cast< XIndexReplace* >(this) ) ); + } + else if ( aType == cppu::UnoType<XIndexAccess>::get()) + { + if (_xIndexAccess.is()) + return Any( Reference< XIndexAccess >( static_cast< XIndexAccess* >(this) ) ); + } + else if ( aType == cppu::UnoType<XEnumerationAccess>::get()) + { + if (_xEnumerationAccess.is()) + return Any( Reference< XEnumerationAccess >( static_cast< XEnumerationAccess* >(this) ) ); + } + else if ( aType == cppu::UnoType<XElementAccess>::get()) + { + if (_xElementAccess.is()) + { + return Any( Reference< XElementAccess >( + static_cast< XElementAccess* >(static_cast< XNameContainer* >(this)) ) ); + } + } + else if ( aType == cppu::UnoType<XInvocation2>::get()) + { + // Invocation does not support XInvocation2, if direct object supports + // XInvocation, but not XInvocation2. + if ( mbFromOLE || + ( _xDirect.is() && _xDirect2.is()) || + (!_xDirect.is() && _xIntrospectionAccess.is() ) ) + { + return Any( Reference< XInvocation2 >( static_cast< XInvocation2* >(this) ) ); + } + } + + return OWeakObject::queryInterface( aType ); +} + + +Any Invocation_Impl::getMaterial() +{ + // AB, 12.2.1999 Make sure that the material is taken when possible + // from the direct Invocation of the Introspection, otherwise structs + // are not handled correctly + Reference<XMaterialHolder> xMaterialHolder; + if( _xDirect.is() ) + { + xMaterialHolder.set( _xDirect, UNO_QUERY ); + //_xDirect->queryInterface( XMaterialHolder::getSmartUik(), xMaterialHolder ); + } + else if( _xIntrospectionAccess.is() ) + { + xMaterialHolder.set( _xIntrospectionAccess, UNO_QUERY ); + //_xIntrospectionAccess->queryInterface( XMaterialHolder::getSmartUik(), xMaterialHolder ); + } + if( xMaterialHolder.is() ) + { + return xMaterialHolder->getMaterial(); + } + return _aMaterial; +} + + +void Invocation_Impl::setMaterial( const Any& rMaterial ) +{ + // set the material first and only once + _aMaterial = rMaterial; + + // First do this outside the guard + _xDirect.set( rMaterial, UNO_QUERY ); + + if( !mbFromOLE && _xDirect.is() ) + { + // Consult object directly + _xElementAccess.set( _xDirect, UNO_QUERY ); + _xEnumerationAccess.set( _xDirect, UNO_QUERY ); + _xIndexAccess.set( _xDirect, UNO_QUERY ); + _xIndexReplace.set( _xDirect, UNO_QUERY ); + _xIndexContainer.set( _xDirect, UNO_QUERY ); + _xNameAccess.set( _xDirect, UNO_QUERY ); + _xNameReplace.set( _xDirect, UNO_QUERY ); + _xNameContainer.set( _xDirect, UNO_QUERY ); + _xENDirect.set( _xDirect, UNO_QUERY ); + _xDirect2.set( _xDirect, UNO_QUERY ); + } + else + { + // Make Invocation on the Introspection + if (xIntrospection.is()) + { + _xIntrospectionAccess = xIntrospection->inspect( _aMaterial ); + if( _xIntrospectionAccess.is() ) + { + _xElementAccess.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XElementAccess>::get()), UNO_QUERY ); + + if( _xElementAccess.is() ) + { + _xEnumerationAccess.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XEnumerationAccess>::get()), UNO_QUERY ); + + _xIndexAccess.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XIndexAccess>::get()), UNO_QUERY ); + + if( _xIndexAccess.is() ) + { + _xIndexReplace.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XIndexReplace>::get()), UNO_QUERY ); + + _xIndexContainer.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XIndexContainer>::get()), UNO_QUERY ); + } + + _xNameAccess.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XNameAccess>::get()), UNO_QUERY ); + + if( _xNameAccess.is() ) + { + _xNameReplace.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XNameReplace>::get()), UNO_QUERY ); + + _xNameContainer.set( + _xIntrospectionAccess->queryAdapter( + cppu::UnoType<XNameContainer>::get()), UNO_QUERY ); + } + } + + _xPropertySet.set( _xIntrospectionAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), + UNO_QUERY ); + + _xENIntrospection.set( _xIntrospectionAccess, UNO_QUERY ); + } + } + } +} + + +OUString Invocation_Impl::getExactName( const OUString& rApproximateName ) +{ + if (_xENDirect.is()) + return _xENDirect->getExactName( rApproximateName ); + + OUString aRet; + if (_xENIntrospection.is()) + aRet = _xENIntrospection->getExactName( rApproximateName ); + return aRet; +} + + +Reference<XIntrospectionAccess> Invocation_Impl::getIntrospection() +{ + if( _xDirect.is() ) + return _xDirect->getIntrospection(); + else + return _xIntrospectionAccess; +} + + +sal_Bool Invocation_Impl::hasMethod( const OUString& Name ) +{ + if (!mbFromOLE && _xDirect.is()) + return _xDirect->hasMethod( Name ); + if( _xIntrospectionAccess.is() ) + return _xIntrospectionAccess->hasMethod( Name, MethodConcept::ALL ^ MethodConcept::DANGEROUS ); + return false; +} + + +sal_Bool Invocation_Impl::hasProperty( const OUString& Name ) +{ + if (_xDirect.is()) + { + bool bRet = _xDirect->hasProperty( Name ); + if (bRet || !mbFromOLE) + return bRet; + } + // PropertySet + if( _xIntrospectionAccess.is() + && _xIntrospectionAccess->hasProperty( Name, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) ) + return true; + // NameAccess + if( _xNameAccess.is() ) + return _xNameAccess->hasByName( Name ); + return false; +} + + +Any Invocation_Impl::getValue( const OUString& PropertyName ) +{ + try + { + if (_xDirect.is()) + return _xDirect->getValue( PropertyName ); + } + catch (Exception &) + { + if (!mbFromOLE) + throw; + } + try + { + // PropertySet + if( _xIntrospectionAccess.is() && _xPropertySet.is() + && _xIntrospectionAccess->hasProperty + ( PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) ) + { + return _xPropertySet->getPropertyValue( PropertyName ); + } + // NameAccess + if( _xNameAccess.is() && _xNameAccess->hasByName( PropertyName ) ) + return _xNameAccess->getByName( PropertyName ); + } + catch (UnknownPropertyException &) + { + throw; + } + catch (RuntimeException &) + { + throw; + } + catch (Exception &) + { + } + + throw UnknownPropertyException( "cannot get value " + PropertyName ); +} + + +void Invocation_Impl::setValue( const OUString& PropertyName, const Any& Value ) +{ + try + { + if (_xDirect.is()) + { + _xDirect->setValue( PropertyName, Value ); + return; + } + } + catch (Exception &) + { + if (!mbFromOLE) + throw; + } + try + { + // Properties + if( _xIntrospectionAccess.is() && _xPropertySet.is() + && _xIntrospectionAccess->hasProperty( + PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) ) + { + Property aProp = _xIntrospectionAccess->getProperty( + PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ); + Reference < XIdlClass > r = TypeToIdlClass( aProp.Type, xCoreReflection ); + if( r->isAssignableFrom( TypeToIdlClass( Value.getValueType(), xCoreReflection ) ) ) + _xPropertySet->setPropertyValue( PropertyName, Value ); + else if( xTypeConverter.is() ) + _xPropertySet->setPropertyValue( + PropertyName, xTypeConverter->convertTo( Value, aProp.Type ) ); + else + throw RuntimeException( "no type converter service!" ); + } + // NameContainer + else if( _xNameContainer.is() ) + { + // Note: This misfeature deliberately not adapted to apply to objects which + // have XNameReplace but not XNameContainer + Any aConv; + Reference < XIdlClass > r = + TypeToIdlClass( _xNameContainer->getElementType(), xCoreReflection ); + if( r->isAssignableFrom(TypeToIdlClass( Value.getValueType(), xCoreReflection ) ) ) + aConv = Value; + else if( xTypeConverter.is() ) + aConv = xTypeConverter->convertTo( Value, _xNameContainer->getElementType() ); + else + throw RuntimeException( "no type converter service!" ); + + // Replace if present, otherwise insert + if (_xNameContainer->hasByName( PropertyName )) + _xNameContainer->replaceByName( PropertyName, aConv ); + else + _xNameContainer->insertByName( PropertyName, aConv ); + } + else + throw UnknownPropertyException( "no introspection nor name container!" ); + } + catch (UnknownPropertyException &) + { + throw; + } + catch (CannotConvertException &) + { + throw; + } + catch (InvocationTargetException &) + { + throw; + } + catch (RuntimeException &) + { + throw; + } + catch (const Exception & exc) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw InvocationTargetException( + "exception occurred in setValue(): " + exc.Message, + Reference< XInterface >(), anyEx ); + } +} + + +Any Invocation_Impl::invoke( const OUString& FunctionName, const Sequence<Any>& InParams, + Sequence<sal_Int16>& OutIndices, Sequence<Any>& OutParams ) +{ + if (!mbFromOLE && _xDirect.is()) + return _xDirect->invoke( FunctionName, InParams, OutIndices, OutParams ); + + if (_xIntrospectionAccess.is()) + { + // throw NoSuchMethodException if not exist + Reference<XIdlMethod> xMethod = _xIntrospectionAccess->getMethod( + FunctionName, MethodConcept::ALL ^ MethodConcept::DANGEROUS ); + + // ParameterInfos + Sequence<ParamInfo> aFParams = xMethod->getParameterInfos(); + const ParamInfo* pFParams = aFParams.getConstArray(); + sal_Int32 nFParamsLen = aFParams.getLength(); + if (nFParamsLen != InParams.getLength()) + { + throw IllegalArgumentException( + "incorrect number of parameters passed invoking function " + FunctionName + + ": expected " + OUString::number(nFParamsLen) + ", got " + OUString::number(InParams.getLength()), + static_cast<OWeakObject *>(this), sal_Int16(1) ); + } + + // IN Parameter + const Any* pInParams = InParams.getConstArray(); + + // Introspection Invoke Parameter + Sequence<Any> aInvokeParams( nFParamsLen ); + Any* pInvokeParams = aInvokeParams.getArray(); + + // OUT Indices + OutIndices.realloc( nFParamsLen ); + sal_Int16* pOutIndices = OutIndices.getArray(); + sal_uInt32 nOutIndex = 0; + + for ( sal_Int32 nPos = 0; nPos < nFParamsLen; ++nPos ) + { + try + { + const ParamInfo& rFParam = pFParams[nPos]; + const Reference<XIdlClass>& rDestType = rFParam.aType; + + // is IN/INOUT parameter? + if (rFParam.aMode != ParamMode_OUT) + { + if (rDestType->isAssignableFrom( TypeToIdlClass( pInParams[nPos].getValueType(), xCoreReflection ) )) + { + pInvokeParams[nPos] = pInParams[nPos]; + } + else if (xTypeConverter.is()) + { + Type aDestType( rDestType->getTypeClass(), rDestType->getName() ); + pInvokeParams[nPos] = xTypeConverter->convertTo( pInParams[nPos], aDestType ); + } + else + { + CannotConvertException aExc; + aExc.Context = *this; + aExc.Message = "invocation type mismatch!"; + throw aExc; + } + } + + // is OUT/INOUT parameter? + if (rFParam.aMode != ParamMode_IN) + { + pOutIndices[nOutIndex] = static_cast<sal_Int16>(nPos); + if (rFParam.aMode == ParamMode_OUT) + rDestType->createObject( pInvokeParams[nPos] ); // default init + ++nOutIndex; + } + } + catch( CannotConvertException& rExc ) + { + rExc.ArgumentIndex = nPos; // Add optional parameter index + throw; + } + } + + // execute Method + Any aRet = xMethod->invoke( _aMaterial, aInvokeParams ); + + // OUT Params + OutIndices.realloc( nOutIndex ); + OutParams.realloc( nOutIndex ); + + std::transform(std::cbegin(OutIndices), std::cend(OutIndices), OutParams.getArray(), + [&pInvokeParams](const sal_Int16 nIndex) -> Any { return pInvokeParams[nIndex]; }); + + return aRet; + } + + RuntimeException aExc; + aExc.Context = *this; + aExc.Message = "invocation lacking of introspection access!"; + throw aExc; +} + +namespace { + +// Struct to optimize sorting +struct MemberItem +{ + OUString aName; + + // Defines where the member comes from + enum class Mode { NameAccess, PropertySet, Method }; + Mode eMode; + + // Index to respective sequence + // (Index to NameAccess sequence for eMode==Mode::NameAccess etc.) + sal_Int32 nIndex; +}; + +} + +// Implementation of getting name or info +// String sequence will be filled when pStringSeq != NULL +// Info sequence will be filled when pInfoSeq != NULL +void Invocation_Impl::getInfoSequenceImpl +( + Sequence< OUString >* pStringSeq, + Sequence< InvocationInfo >* pInfoSeq +) +{ + //Sequence< OUString > aStrSeq; + //if( !pStringSeq ) + //pStringSeq = &aStrSeq; + + + // Get all needed sequences + Sequence<OUString> aNameAccessNames; + Sequence<Property> aPropertySeq; + Sequence< Reference< XIdlMethod > > aMethodSeq; + + if( _xNameAccess.is() ) + { + aNameAccessNames = _xNameAccess->getElementNames(); + } + + if( _xIntrospectionAccess.is() ) + { + aPropertySeq = _xIntrospectionAccess->getProperties + ( PropertyConcept::ALL - PropertyConcept::DANGEROUS ); + + aMethodSeq = _xIntrospectionAccess->getMethods + ( MethodConcept::ALL - MethodConcept::DANGEROUS ); + } + + sal_Int32 nNameAccessCount = aNameAccessNames.getLength(); + sal_Int32 nPropertyCount = aPropertySeq.getLength(); + sal_Int32 nMethodCount = aMethodSeq.getLength(); + sal_Int32 nTotalCount = nNameAccessCount + nPropertyCount + nMethodCount; + + // Create and fill array of MemberItems + std::unique_ptr< MemberItem []> pItems( new MemberItem[ nTotalCount ] ); + const OUString* pStrings = aNameAccessNames.getConstArray(); + const Property* pProps = aPropertySeq.getConstArray(); + const Reference< XIdlMethod >* pMethods = aMethodSeq.getConstArray(); + + // Fill array of MemberItems + sal_Int32 i, iTotal = 0; + + // Name Access + for( i = 0 ; i < nNameAccessCount ; i++, iTotal++ ) + { + MemberItem& rItem = pItems[ iTotal ]; + rItem.aName = pStrings[ i ]; + rItem.eMode = MemberItem::Mode::NameAccess; + rItem.nIndex = i; + } + + // Property set + for( i = 0 ; i < nPropertyCount ; i++, iTotal++ ) + { + MemberItem& rItem = pItems[ iTotal ]; + rItem.aName = pProps[ i ].Name; + rItem.eMode = MemberItem::Mode::PropertySet; + rItem.nIndex = i; + } + + // Methods + for( i = 0 ; i < nMethodCount ; i++, iTotal++ ) + { + MemberItem& rItem = pItems[ iTotal ]; + Reference< XIdlMethod > xMethod = pMethods[ i ]; + rItem.aName = xMethod->getName(); + rItem.eMode = MemberItem::Mode::Method; + rItem.nIndex = i; + } + + // Setting up result sequences + OUString* pRetStrings = nullptr; + if( pStringSeq ) + { + pStringSeq->realloc( nTotalCount ); + pRetStrings = pStringSeq->getArray(); + } + + InvocationInfo* pRetInfos = nullptr; + if( pInfoSeq ) + { + pInfoSeq->realloc( nTotalCount ); + pRetInfos = pInfoSeq->getArray(); + } + + // Fill result sequences in the correct order of members + for( iTotal = 0 ; iTotal < nTotalCount ; iTotal++ ) + { + MemberItem& rItem = pItems[ iTotal ]; + if( pRetStrings ) + { + pRetStrings[ iTotal ] = rItem.aName; + } + + if( pRetInfos ) + { + if( rItem.eMode == MemberItem::Mode::NameAccess ) + { + fillInfoForNameAccess( pRetInfos[ iTotal ], rItem.aName ); + } + else if( rItem.eMode == MemberItem::Mode::PropertySet ) + { + fillInfoForProperty( pRetInfos[ iTotal ], pProps[ rItem.nIndex ] ); + } + else if( rItem.eMode == MemberItem::Mode::Method ) + { + fillInfoForMethod( pRetInfos[ iTotal ], pMethods[ rItem.nIndex ] ); + } + } + } +} + +// XInvocation2 +Sequence< OUString > SAL_CALL Invocation_Impl::getMemberNames( ) +{ + if( _xDirect2.is() ) + { + return _xDirect2->getMemberNames(); + } + Sequence< OUString > aRetSeq; + getInfoSequenceImpl( &aRetSeq, nullptr ); + return aRetSeq; +} + +Sequence< InvocationInfo > SAL_CALL Invocation_Impl::getInfo( ) +{ + if( _xDirect2.is() ) + { + return _xDirect2->getInfo(); + } + Sequence< InvocationInfo > aRetSeq; + getInfoSequenceImpl( nullptr, &aRetSeq ); + return aRetSeq; +} + +InvocationInfo SAL_CALL Invocation_Impl::getInfoForName( const OUString& aName, sal_Bool bExact ) +{ + if( _xDirect2.is() ) + { + return _xDirect2->getInfoForName( aName, bExact ); + } + + bool bFound = false; + OUString aExactName = aName; + InvocationInfo aRetInfo; + + if( bExact ) + aExactName = getExactName( aName ); + if( !aExactName.isEmpty() ) + { + if( _xIntrospectionAccess->hasMethod( aExactName, MethodConcept::ALL ^ MethodConcept::DANGEROUS ) ) + { + Reference<XIdlMethod> xMethod = _xIntrospectionAccess->getMethod + ( aExactName, MethodConcept::ALL ^ MethodConcept::DANGEROUS ); + fillInfoForMethod( aRetInfo, xMethod ); + bFound = true; + } + else + { + if( _xIntrospectionAccess.is() && _xIntrospectionAccess->hasProperty + ( aExactName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) ) + { + Property aProp = _xIntrospectionAccess->getProperty + ( aExactName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ); + fillInfoForProperty( aRetInfo, aProp ); + bFound = true; + } + // NameAccess + else if( _xNameAccess.is() && _xNameAccess->hasByName( aExactName ) ) + { + fillInfoForNameAccess( aRetInfo, aExactName ); + bFound = true; + } + } + } + if( !bFound ) + { + throw IllegalArgumentException( + "getExactName(), Unknown name " + aName, + static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 ); + } + return aRetInfo; +} + +// Helper functions to fill InvocationInfo for XNameAccess +void Invocation_Impl::fillInfoForNameAccess +( + InvocationInfo& rInfo, + const OUString& aName +) +{ + rInfo.aName = aName; + rInfo.eMemberType = MemberType_PROPERTY; + rInfo.PropertyAttribute = 0; + if( !_xNameContainer.is() ) + { + rInfo.PropertyAttribute = PropertyAttribute::READONLY; + } + rInfo.aType = _xNameAccess->getElementType(); +} + +void Invocation_Impl::fillInfoForProperty +( + InvocationInfo& rInfo, + const Property& rProp +) +{ + rInfo.aName = rProp.Name; + rInfo.eMemberType = MemberType_PROPERTY; + rInfo.PropertyAttribute = rProp.Attributes; + rInfo.aType = rProp.Type; +} + +void Invocation_Impl::fillInfoForMethod +( + InvocationInfo& rInfo, + const Reference< XIdlMethod >& xMethod +) +{ + rInfo.aName = xMethod->getName(); + rInfo.eMemberType = MemberType_METHOD; + Reference< XIdlClass > xReturnClass = xMethod->getReturnType(); + Type aReturnType( xReturnClass->getTypeClass(), xReturnClass->getName() ); + rInfo.aType = aReturnType; + Sequence<ParamInfo> aParamInfos = xMethod->getParameterInfos(); + sal_Int32 nParamCount = aParamInfos.getLength(); + if( nParamCount <= 0 ) + return; + + const ParamInfo* pInfo = aParamInfos.getConstArray(); + + rInfo.aParamTypes.realloc( nParamCount ); + Type* pParamTypes = rInfo.aParamTypes.getArray(); + rInfo.aParamModes.realloc( nParamCount ); + ParamMode* pParamModes = rInfo.aParamModes.getArray(); + + for( sal_Int32 i = 0 ; i < nParamCount ; i++ ) + { + Reference< XIdlClass > xParamClass = pInfo[i].aType; + Type aParamType( xParamClass->getTypeClass(), xParamClass->getName() ); + pParamTypes[ i ] = aParamType; + pParamModes[ i ] = pInfo[i].aMode; + } +} + + +// XTypeProvider +Sequence< Type > SAL_CALL Invocation_Impl::getTypes() +{ + static Sequence<Type> s_types = [this]() { + std::vector<Type> tmp { + cppu::UnoType<XTypeProvider>::get(), + cppu::UnoType<XWeak>::get(), + cppu::UnoType<XInvocation>::get(), + cppu::UnoType<XMaterialHolder>::get() }; + + // Invocation does not support XExactName if direct object supports + // XInvocation, but not XExactName. + if ((_xDirect.is() && _xENDirect.is()) || (!_xDirect.is() && _xENIntrospection.is())) + tmp.push_back(cppu::UnoType<XExactName>::get()); + if (_xNameContainer.is()) + tmp.push_back(cppu::UnoType<XNameContainer>::get()); + if (_xNameReplace.is()) + tmp.push_back(cppu::UnoType<XNameReplace>::get()); + if (_xNameAccess.is()) + tmp.push_back(cppu::UnoType<XNameAccess>::get()); + if (_xIndexContainer.is()) + tmp.push_back(cppu::UnoType<XIndexContainer>::get()); + if (_xIndexReplace.is()) + tmp.push_back(cppu::UnoType<XIndexReplace>::get()); + if (_xIndexAccess.is()) + tmp.push_back(cppu::UnoType<XIndexAccess>::get()); + if (_xEnumerationAccess.is()) + tmp.push_back(cppu::UnoType<XEnumerationAccess>::get()); + if (_xElementAccess.is()) + tmp.push_back(cppu::UnoType<XElementAccess>::get()); + // Invocation does not support XInvocation2, if direct object supports + // XInvocation, but not XInvocation2. + if ((_xDirect.is() && _xDirect2.is()) || (!_xDirect.is() && _xIntrospectionAccess.is())) + tmp.push_back(cppu::UnoType<XInvocation2>::get()); + + return comphelper::containerToSequence(tmp); + }(); + return s_types; +} + +Sequence< sal_Int8 > SAL_CALL Invocation_Impl::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +namespace { + +class InvocationService + : public WeakImplHelper< XSingleServiceFactory, XServiceInfo > +{ +public: + explicit InvocationService( const Reference<XComponentContext> & xCtx ); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XSingleServiceFactory + Reference<XInterface> SAL_CALL createInstance() override; + Reference<XInterface> SAL_CALL createInstanceWithArguments( + const Sequence<Any>& rArguments ) override; +private: + Reference<XComponentContext> mxCtx; + Reference<XMultiComponentFactory> mxSMgr; + Reference<XTypeConverter> xTypeConverter; + Reference<XIntrospection> xIntrospection; + Reference<XIdlReflection> xCoreReflection; +}; + +} + +InvocationService::InvocationService( const Reference<XComponentContext> & xCtx ) + : mxCtx( xCtx ) + , mxSMgr( xCtx->getServiceManager() ) + , xCoreReflection( css::reflection::theCoreReflection::get(mxCtx) ) +{ + xTypeConverter.set( + mxSMgr->createInstanceWithContext( "com.sun.star.script.Converter", xCtx ), + UNO_QUERY ); + xIntrospection = theIntrospection::get(xCtx); +} + +// XServiceInfo +OUString InvocationService::getImplementationName() +{ + return "com.sun.star.comp.stoc.Invocation"; +} + +// XServiceInfo +sal_Bool InvocationService::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > InvocationService::getSupportedServiceNames() +{ + return { "com.sun.star.script.Invocation" }; +} + + +Reference<XInterface> InvocationService::createInstance() +{ + //TODO:throw( Exception("no default construction of invocation adapter possible!", *this) ); + return Reference<XInterface>(); // dummy +} + + +Reference<XInterface> InvocationService::createInstanceWithArguments( + const Sequence<Any>& rArguments ) +{ + if (rArguments.getLength() == 2) + { + OUString aArg1; + if ((rArguments[1] >>= aArg1) && + aArg1 == "FromOLE") + { + return Reference< XInterface > + ( *new Invocation_Impl( *rArguments.getConstArray(), + xTypeConverter, xIntrospection, xCoreReflection, true ) ); + } + } + if (rArguments.getLength() == 1) + { + return Reference< XInterface > + ( *new Invocation_Impl( *rArguments.getConstArray(), + xTypeConverter, xIntrospection, xCoreReflection, false ) ); + } + + //TODO:throw( Exception("no default construction of invocation adapter possible!", *this) ); + return Reference<XInterface>(); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +stoc_InvocationService_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new InvocationService(context)); +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/invocation_adapterfactory/iafactory.cxx b/stoc/source/invocation_adapterfactory/iafactory.cxx new file mode 100644 index 000000000..894b00f42 --- /dev/null +++ b/stoc/source/invocation_adapterfactory/iafactory.cxx @@ -0,0 +1,882 @@ +/* -*- 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 <osl/diagnose.h> +#include <osl/interlck.h> +#include <osl/mutex.hxx> +#include <o3tl/sorted_vector.hxx> +#include <sal/log.hxx> + +#include <uno/dispatcher.h> +#include <uno/data.h> +#include <uno/any2.h> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/XInvocationAdapterFactory.hpp> +#include <com/sun/star/script/XInvocationAdapterFactory2.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/reflection/InvocationTargetException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <unordered_map> +#include <vector> + +using namespace ::std; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace css::uno; + +namespace stoc_invadp +{ + + +namespace { + +struct hash_ptr +{ + size_t operator() ( void * p ) const + { return reinterpret_cast<size_t>(p); } +}; + +} + +typedef o3tl::sorted_vector< void * > t_ptr_set; +typedef std::unordered_map< void *, t_ptr_set, hash_ptr > t_ptr_map; + +namespace { + +class FactoryImpl + : public ::cppu::WeakImplHelper< lang::XServiceInfo, + script::XInvocationAdapterFactory, + script::XInvocationAdapterFactory2 > +{ +public: + Mapping m_aUno2Cpp; + Mapping m_aCpp2Uno; + uno_Interface * m_pConverter; + + typelib_TypeDescription * m_pInvokMethodTD; + typelib_TypeDescription * m_pSetValueTD; + typelib_TypeDescription * m_pGetValueTD; + typelib_TypeDescription * m_pAnySeqTD; + typelib_TypeDescription * m_pShortSeqTD; + typelib_TypeDescription * m_pConvertToTD; + + Mutex m_mutex; + t_ptr_map m_receiver2adapters; + + explicit FactoryImpl( Reference< XComponentContext > const & xContext ); + virtual ~FactoryImpl() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XInvocationAdapterFactory + virtual Reference< XInterface > SAL_CALL createAdapter( + const Reference< script::XInvocation > & xReceiver, const Type & rType ) override; + // XInvocationAdapterFactory2 + virtual Reference< XInterface > SAL_CALL createAdapter( + const Reference< script::XInvocation > & xReceiver, + const Sequence< Type > & rTypes ) override; +}; +struct AdapterImpl; + +struct InterfaceAdapterImpl : public uno_Interface +{ + AdapterImpl * m_pAdapter; + typelib_InterfaceTypeDescription * m_pTypeDescr; +}; + +struct AdapterImpl +{ + oslInterlockedCount m_nRef; + FactoryImpl * m_pFactory; + void * m_key; // map key + uno_Interface * m_pReceiver; // XInvocation receiver + + std::vector<InterfaceAdapterImpl> m_vInterfaces; + + // XInvocation calls + void getValue( + const typelib_TypeDescription * pMemberType, + void * pReturn, uno_Any ** ppException ); + void setValue( + const typelib_TypeDescription * pMemberType, + void * pArgs[], uno_Any ** ppException ); + void invoke( + const typelib_TypeDescription * pMemberType, + void * pReturn, void * pArgs[], uno_Any ** ppException ); + + bool coerce_assign( + void * pDest, typelib_TypeDescriptionReference * pType, + uno_Any * pSource, uno_Any * pExc ); + inline bool coerce_construct( + void * pDest, typelib_TypeDescriptionReference * pType, + uno_Any * pSource, uno_Any * pExc ); + + inline void acquire(); + inline void release(); + inline ~AdapterImpl(); + inline AdapterImpl( + void * key, Reference< script::XInvocation > const & xReceiver, + const Sequence< Type > & rTypes, + FactoryImpl * pFactory ); + + // Copy assignment is forbidden and not implemented. + AdapterImpl (const AdapterImpl &) = delete; + AdapterImpl & operator= (const AdapterImpl &) = delete; +}; + +} + +inline AdapterImpl::~AdapterImpl() +{ + for ( size_t nPos = m_vInterfaces.size(); nPos--; ) + { + ::typelib_typedescription_release( + &m_vInterfaces[ nPos ].m_pTypeDescr->aBase ); + } + + (*m_pReceiver->release)( m_pReceiver ); + m_pFactory->release(); +} + +inline void AdapterImpl::acquire() +{ + osl_atomic_increment( &m_nRef ); +} + +inline void AdapterImpl::release() +{ + bool delete_this = false; + { + MutexGuard guard( m_pFactory->m_mutex ); + if (! osl_atomic_decrement( &m_nRef )) + { + t_ptr_map::iterator iFind( + m_pFactory->m_receiver2adapters.find( m_key ) ); + OSL_ASSERT( m_pFactory->m_receiver2adapters.end() != iFind ); + t_ptr_set & adapter_set = iFind->second; + if (adapter_set.erase( this ) != 1) { + OSL_ASSERT( false ); + } + if (adapter_set.empty()) + { + m_pFactory->m_receiver2adapters.erase( iFind ); + } + delete_this = true; + } + } + if (delete_this) + delete this; +} + + +static void constructRuntimeException( + uno_Any * pExc, const OUString & rMsg ) +{ + RuntimeException exc( rMsg ); + // no conversion needed due to binary compatibility + no convertible type + ::uno_type_any_construct( + pExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), nullptr ); +} + + +static bool type_equals( + typelib_TypeDescriptionReference * pType1, + typelib_TypeDescriptionReference * pType2 ) +{ + return (pType1 == pType2 || + (pType1->pTypeName->length == pType2->pTypeName->length && + 0 == ::rtl_ustr_compare( + pType1->pTypeName->buffer, pType2->pTypeName->buffer ))); +} + + +bool AdapterImpl::coerce_assign( + void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource, + uno_Any * pOutExc ) +{ + if (typelib_TypeClass_ANY == pType->eTypeClass) + { + ::uno_type_any_assign( + static_cast<uno_Any *>(pDest), pSource->pData, pSource->pType, nullptr, nullptr ); + return true; + } + if (::uno_type_assignData( + pDest, pType, pSource->pData, pSource->pType, nullptr, nullptr, nullptr )) + { + return true; + } + else // try type converter + { + uno_Any ret; + void * args[ 2 ]; + args[ 0 ] = pSource; + args[ 1 ] = &pType; + uno_Any exc; + uno_Any * p_exc = &exc; + + // converTo() + (*m_pFactory->m_pConverter->pDispatcher)( + m_pFactory->m_pConverter, + m_pFactory->m_pConvertToTD, &ret, args, &p_exc ); + + if (p_exc) // exception occurred + { + OSL_ASSERT( + p_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION ); + if (typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType<RuntimeException>::get().getTypeLibType(), + p_exc->pType )) + { + // is RuntimeException or derived: rethrow + uno_type_any_construct( + pOutExc, p_exc->pData, p_exc->pType, nullptr ); + } + else + { + // set runtime exception + constructRuntimeException( + pOutExc, "type coercion failed: " + + static_cast< Exception const * >( + p_exc->pData )->Message ); + } + ::uno_any_destruct( p_exc, nullptr ); + // pOutExc constructed + return false; + } + else + { + bool succ = ::uno_type_assignData( + pDest, pType, ret.pData, ret.pType, nullptr, nullptr, nullptr ); + ::uno_any_destruct( &ret, nullptr ); + OSL_ENSURE( + succ, "### conversion succeeded, but assignment failed!?" ); + if (! succ) + { + // set runtime exception + constructRuntimeException( + pOutExc, + "type coercion failed: " + "conversion succeeded, but assignment failed?!" ); + } + return succ; + } + } +} + +inline bool AdapterImpl::coerce_construct( + void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource, + uno_Any * pExc ) +{ + if (typelib_TypeClass_ANY == pType->eTypeClass) + { + ::uno_type_copyData( pDest, pSource, pType, nullptr ); + return true; + } + if (type_equals( pType, pSource->pType)) + { + ::uno_type_copyData( pDest, pSource->pData, pType, nullptr ); + return true; + } + ::uno_type_constructData( pDest, pType ); + return coerce_assign( pDest, pType, pSource, pExc ); +} + + +static void handleInvokExc( uno_Any * pDest, uno_Any * pSource ) +{ + OUString const & name = + OUString::unacquired( &pSource->pType->pTypeName ); + + if ( name == "com.sun.star.reflection.InvocationTargetException" ) + { + // unwrap invocation target exception + uno_Any * target_exc = + &static_cast< reflection::InvocationTargetException * >( + pSource->pData )->TargetException; + ::uno_type_any_construct( + pDest, target_exc->pData, target_exc->pType, nullptr ); + } + else // all other exceptions are wrapped to RuntimeException + { + if (typelib_TypeClass_EXCEPTION == pSource->pType->eTypeClass) + { + constructRuntimeException( + pDest, static_cast<Exception const *>(pSource->pData)->Message ); + } + else + { + constructRuntimeException( + pDest, "no exception has been thrown via invocation?!" ); + } + } +} + +void AdapterImpl::getValue( + const typelib_TypeDescription * pMemberType, + void * pReturn, uno_Any ** ppException ) +{ + uno_Any aInvokRet; + void * pInvokArgs[1]; + pInvokArgs[0] = const_cast<rtl_uString **>( + &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName); + uno_Any aInvokExc; + uno_Any * pInvokExc = &aInvokExc; + + // getValue() + (*m_pReceiver->pDispatcher)( + m_pReceiver, m_pFactory->m_pGetValueTD, + &aInvokRet, pInvokArgs, &pInvokExc ); + + if (pInvokExc) // getValue() call exception + { + handleInvokExc( *ppException, pInvokExc ); + ::uno_any_destruct( pInvokExc, nullptr ); // cleanup + } + else // invocation call succeeded + { + if (coerce_construct( + pReturn, + reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>( + pMemberType)->pAttributeTypeRef, + &aInvokRet, *ppException )) + { + *ppException = nullptr; // no exceptions be thrown + } + ::uno_any_destruct( &aInvokRet, nullptr ); + } +} + +void AdapterImpl::setValue( + const typelib_TypeDescription * pMemberType, + void * pArgs[], uno_Any ** ppException ) +{ + uno_Any aInvokVal; + ::uno_type_any_construct( + &aInvokVal, pArgs[0], + reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>( + pMemberType)->pAttributeTypeRef, nullptr ); + + void * pInvokArgs[2]; + pInvokArgs[0] = const_cast<rtl_uString **>( + &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName); + pInvokArgs[1] = &aInvokVal; + uno_Any aInvokExc; + uno_Any * pInvokExc = &aInvokExc; + + // setValue() + (*m_pReceiver->pDispatcher)( + m_pReceiver, m_pFactory->m_pSetValueTD, nullptr, pInvokArgs, &pInvokExc ); + + if (pInvokExc) // setValue() call exception + { + handleInvokExc( *ppException, pInvokExc ); + ::uno_any_destruct( pInvokExc, nullptr ); // cleanup + } + else // invocation call succeeded + { + *ppException = nullptr; // no exceptions be thrown + } + + ::uno_any_destruct( &aInvokVal, nullptr ); // cleanup +} + +void AdapterImpl::invoke( + const typelib_TypeDescription * pMemberType, + void * pReturn, void * pArgs[], uno_Any ** ppException ) +{ + sal_Int32 nParams = + reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType)->nParams; + typelib_MethodParameter * pFormalParams = + reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType)->pParams; + + // in params + uno_Sequence * pInParamsSeq = nullptr; + ::uno_sequence_construct( + &pInParamsSeq, m_pFactory->m_pAnySeqTD, nullptr, nParams, nullptr ); + uno_Any * pInAnys = reinterpret_cast<uno_Any *>(pInParamsSeq->elements); + sal_Int32 nOutParams = 0; + sal_Int32 nPos; + for ( nPos = nParams; nPos--; ) + { + typelib_MethodParameter const & rParam = pFormalParams[nPos]; + if (rParam.bIn) // is in/inout param + { + ::uno_type_any_assign( + &pInAnys[nPos], pArgs[nPos], rParam.pTypeRef, nullptr, nullptr ); + } + // else: pure out is empty any + + if (rParam.bOut) + ++nOutParams; + } + + // out params, out indices + uno_Sequence * pOutIndices; + uno_Sequence * pOutParams; + // return value + uno_Any aInvokRet; + // perform call + void * pInvokArgs[4]; + pInvokArgs[0] = const_cast<rtl_uString **>( + &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName); + pInvokArgs[1] = &pInParamsSeq; + pInvokArgs[2] = &pOutIndices; + pInvokArgs[3] = &pOutParams; + uno_Any aInvokExc; + uno_Any * pInvokExc = &aInvokExc; + + // invoke() call + (*m_pReceiver->pDispatcher)( + m_pReceiver, m_pFactory->m_pInvokMethodTD, + &aInvokRet, pInvokArgs, &pInvokExc ); + + if (pInvokExc) + { + handleInvokExc( *ppException, pInvokExc ); + ::uno_any_destruct( pInvokExc, nullptr ); // cleanup + } + else // no invocation exception + { + // write changed out params + OSL_ENSURE( + pOutParams->nElements == nOutParams && + pOutIndices->nElements == nOutParams, + "### out params lens differ!" ); + if (pOutParams->nElements == nOutParams && + pOutIndices->nElements == nOutParams) + { + sal_Int16 * pIndices = reinterpret_cast<sal_Int16 *>(pOutIndices->elements); + uno_Any * pOut = reinterpret_cast<uno_Any *>(pOutParams->elements); + for ( nPos = 0; nPos < nOutParams; ++nPos ) + { + sal_Int32 nIndex = pIndices[nPos]; + OSL_ENSURE( nIndex < nParams, "### illegal index!" ); + typelib_MethodParameter const & rParam = pFormalParams[nIndex]; + bool succ; + if (rParam.bIn) // is in/inout param + { + succ = coerce_assign( + pArgs[nIndex], rParam.pTypeRef, &pOut[nPos], + *ppException ); + } + else // pure out + { + succ = coerce_construct( + pArgs[nIndex], rParam.pTypeRef, &pOut[nPos], + *ppException ); + } + if (! succ) // cleanup of out params + { + for ( sal_Int32 n = 0; n <= nPos; ++n ) + { + sal_Int32 nIndex2 = pIndices[n]; + OSL_ENSURE( nIndex2 < nParams, "### illegal index!" ); + typelib_MethodParameter const & rParam2 = + pFormalParams[nIndex2]; + if (! rParam2.bIn) // is pure out param + { + ::uno_type_destructData( + pArgs[nIndex2], rParam2.pTypeRef, nullptr ); + } + } + } + } + if (nPos == pOutIndices->nElements) + { + // out param copy ok; write return value + if (coerce_construct( + pReturn, + reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>( + pMemberType)->pReturnTypeRef, + &aInvokRet, *ppException )) + { + *ppException = nullptr; // no exception + } + } + } + else + { + // set runtime exception + constructRuntimeException( + *ppException, + "out params lengths differ after invocation call!" ); + } + // cleanup invok out params + ::uno_destructData( &pOutIndices, m_pFactory->m_pShortSeqTD, nullptr ); + ::uno_destructData( &pOutParams, m_pFactory->m_pAnySeqTD, nullptr ); + // cleanup invok return value + ::uno_any_destruct( &aInvokRet, nullptr ); + } + // cleanup constructed in params + ::uno_destructData( &pInParamsSeq, m_pFactory->m_pAnySeqTD, nullptr ); +} + +extern "C" +{ + +static void adapter_acquire( uno_Interface * pUnoI ) +{ + static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->acquire(); +} + +static void adapter_release( uno_Interface * pUnoI ) +{ + static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->release(); +} + +static void adapter_dispatch( + uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType, + void * pReturn, void * pArgs[], uno_Any ** ppException ) +{ + // query to emulated interface + switch (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->nPosition) + { + case 0: // queryInterface() + { + AdapterImpl * that = + static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter; + *ppException = nullptr; // no exc + typelib_TypeDescriptionReference * pDemanded = + *static_cast<typelib_TypeDescriptionReference **>(pArgs[0]); + // pInterfaces[0] is XInterface + for ( size_t nPos = 0; nPos < that->m_vInterfaces.size(); ++nPos ) + { + typelib_InterfaceTypeDescription * pTD = + that->m_vInterfaces[nPos].m_pTypeDescr; + while (pTD) + { + if (type_equals( pTD->aBase.pWeakRef, pDemanded )) + { + uno_Interface * pUnoI2 = &that->m_vInterfaces[nPos]; + ::uno_any_construct( + static_cast<uno_Any *>(pReturn), &pUnoI2, + &pTD->aBase, nullptr ); + return; + } + pTD = pTD->pBaseTypeDescription; + } + } + ::uno_any_construct( static_cast<uno_Any *>(pReturn), nullptr, nullptr, nullptr ); // clear() + break; + } + case 1: // acquire() + *ppException = nullptr; // no exc + adapter_acquire( pUnoI ); + break; + case 2: // release() + *ppException = nullptr; // no exc + adapter_release( pUnoI ); + break; + + default: + { + AdapterImpl * that = + static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter; + if (pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD) + { + that->invoke( pMemberType, pReturn, pArgs, ppException ); + } + else // attribute + { + if (pReturn) + that->getValue( pMemberType, pReturn, ppException ); + else + that->setValue( pMemberType, pArgs, ppException ); + } + } + } +} +} + +AdapterImpl::AdapterImpl( + void * key, Reference< script::XInvocation > const & xReceiver, + const Sequence< Type > & rTypes, + FactoryImpl * pFactory ) + : m_nRef( 1 ), + m_pFactory( pFactory ), + m_key( key ), + m_vInterfaces( rTypes.getLength() ) +{ + // init adapters + const Type * pTypes = rTypes.getConstArray(); + for ( sal_Int32 nPos = rTypes.getLength(); nPos--; ) + { + InterfaceAdapterImpl * pInterface = &m_vInterfaces[nPos]; + pInterface->acquire = adapter_acquire; + pInterface->release = adapter_release; + pInterface->pDispatcher = adapter_dispatch; + pInterface->m_pAdapter = this; + pInterface->m_pTypeDescr = nullptr; + pTypes[nPos].getDescription( + reinterpret_cast<typelib_TypeDescription **>(&pInterface->m_pTypeDescr) ); + OSL_ASSERT( pInterface->m_pTypeDescr ); + if (! pInterface->m_pTypeDescr) + { + for ( sal_Int32 n = 0; n < nPos; ++n ) + { + ::typelib_typedescription_release( + &m_vInterfaces[ n ].m_pTypeDescr->aBase ); + } + throw RuntimeException( + "cannot retrieve all interface type infos!" ); + } + } + + // map receiver + m_pReceiver = static_cast<uno_Interface *>(m_pFactory->m_aCpp2Uno.mapInterface( + xReceiver.get(), cppu::UnoType<decltype(xReceiver)>::get() )); + OSL_ASSERT( nullptr != m_pReceiver ); + if (! m_pReceiver) + { + throw RuntimeException( "cannot map receiver!" ); + } + + m_pFactory->acquire(); +} + + +FactoryImpl::FactoryImpl( Reference< XComponentContext > const & xContext ) + : m_aUno2Cpp(Mapping( UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME )), + m_aCpp2Uno(Mapping( CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO)), + m_pInvokMethodTD( nullptr ), + m_pSetValueTD( nullptr ), + m_pGetValueTD( nullptr ), + m_pAnySeqTD( nullptr ), + m_pShortSeqTD( nullptr ), + m_pConvertToTD( nullptr ) +{ + // C++/UNO bridge + OSL_ENSURE( + m_aUno2Cpp.is() && m_aCpp2Uno.is(), "### no uno / C++ mappings!" ); + + // type converter + Reference< script::XTypeConverter > xConverter( + xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.script.Converter", + xContext ), + UNO_QUERY_THROW ); + m_pConverter = static_cast<uno_Interface *>(m_aCpp2Uno.mapInterface( + xConverter.get(), cppu::UnoType<decltype(xConverter)>::get() )); + OSL_ASSERT( nullptr != m_pConverter ); + + // some type info: + // sequence< any > + Type const & rAnySeqType = cppu::UnoType<Sequence< Any >>::get(); + rAnySeqType.getDescription( &m_pAnySeqTD ); + // sequence< short > + const Type & rShortSeqType = + cppu::UnoType<Sequence< sal_Int16 >>::get(); + rShortSeqType.getDescription( &m_pShortSeqTD ); + // script.XInvocation + typelib_TypeDescription * pTD = nullptr; + const Type & rInvType = cppu::UnoType<script::XInvocation>::get(); + TYPELIB_DANGER_GET( &pTD, rInvType.getTypeLibType() ); + typelib_InterfaceTypeDescription * pITD; + pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD); + if( ! pITD->aBase.bComplete ) + typelib_typedescription_complete( &pTD ); + ::typelib_typedescriptionreference_getDescription( + &m_pInvokMethodTD, pITD->ppMembers[ 1 ] ); // invoke() + ::typelib_typedescriptionreference_getDescription( + &m_pSetValueTD, pITD->ppMembers[ 2 ] ); // setValue() + ::typelib_typedescriptionreference_getDescription( + &m_pGetValueTD, pITD->ppMembers[ 3 ] ); // getValue() + // script.XTypeConverter + const Type & rTCType = + cppu::UnoType<script::XTypeConverter>::get(); + TYPELIB_DANGER_GET( &pTD, rTCType.getTypeLibType() ); + pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD); + ::typelib_typedescriptionreference_getDescription( + &m_pConvertToTD, pITD->ppMembers[ 0 ] ); // convertTo() + TYPELIB_DANGER_RELEASE( pTD ); + + if (!m_pInvokMethodTD || !m_pSetValueTD || !m_pGetValueTD || + !m_pConvertToTD || + !m_pAnySeqTD || !m_pShortSeqTD) + { + throw RuntimeException( "missing type descriptions!" ); + } +} + +FactoryImpl::~FactoryImpl() +{ + ::typelib_typedescription_release( m_pInvokMethodTD ); + ::typelib_typedescription_release( m_pSetValueTD ); + ::typelib_typedescription_release( m_pGetValueTD ); + ::typelib_typedescription_release( m_pAnySeqTD ); + ::typelib_typedescription_release( m_pShortSeqTD ); + ::typelib_typedescription_release( m_pConvertToTD ); + + (*m_pConverter->release)( m_pConverter ); + +#if OSL_DEBUG_LEVEL > 0 + assert(m_receiver2adapters.empty() && "still adapters out there!?"); +#endif +} + + +static AdapterImpl * lookup_adapter( + t_ptr_set ** pp_adapter_set, + t_ptr_map & map, void * key, Sequence< Type > const & rTypes ) +{ + t_ptr_set & adapters_set = map[ key ]; + *pp_adapter_set = &adapters_set; + if (adapters_set.empty()) + return nullptr; // shortcut + // find matching adapter + Type const * pTypes = rTypes.getConstArray(); + sal_Int32 nTypes = rTypes.getLength(); + for (const auto& rpAdapter : adapters_set) + { + AdapterImpl * that = static_cast< AdapterImpl * >( rpAdapter ); + // iterate through all types if that is a matching adapter + sal_Int32 nPosTypes; + for ( nPosTypes = nTypes; nPosTypes--; ) + { + Type const & rType = pTypes[ nPosTypes ]; + // find in adapter's type list + sal_Int32 nPos; + for ( nPos = that->m_vInterfaces.size(); nPos--; ) + { + if (::typelib_typedescriptionreference_isAssignableFrom( + rType.getTypeLibType(), + that->m_vInterfaces[ nPos ].m_pTypeDescr->aBase.pWeakRef )) + { + // found + break; + } + } + if (nPos < 0) // type not found => next adapter + break; + } + if (nPosTypes < 0) // all types found + return that; + } + return nullptr; +} + +// XInvocationAdapterFactory2 impl + +Reference< XInterface > FactoryImpl::createAdapter( + const Reference< script::XInvocation > & xReceiver, + const Sequence< Type > & rTypes ) +{ + Reference< XInterface > xRet; + if (xReceiver.is() && rTypes.hasElements()) + { + t_ptr_set * adapter_set; + AdapterImpl * that; + Reference< XInterface > xKey( xReceiver, UNO_QUERY ); + { + ClearableMutexGuard guard( m_mutex ); + that = lookup_adapter( + &adapter_set, m_receiver2adapters, xKey.get(), rTypes ); + if (nullptr == that) // no entry + { + guard.clear(); + // create adapter; already acquired: m_nRef == 1 + AdapterImpl * pNew = + new AdapterImpl( xKey.get(), xReceiver, rTypes, this ); + // lookup again + ClearableMutexGuard guard2( m_mutex ); + that = lookup_adapter( + &adapter_set, m_receiver2adapters, xKey.get(), rTypes ); + if (nullptr == that) // again no entry + { + pair< t_ptr_set::const_iterator, bool > i(adapter_set->insert(pNew)); + SAL_WARN_IF( + !i.second, "stoc", + "set already contains " << *(i.first) << " != " << pNew); + that = pNew; + } + else + { + that->acquire(); + guard2.clear(); + delete pNew; // has never been inserted + } + } + else // found adapter + { + that->acquire(); + } + } + // map one interface to C++ + uno_Interface * pUnoI = that->m_vInterfaces.data(); + m_aUno2Cpp.mapInterface( + reinterpret_cast<void **>(&xRet), pUnoI, cppu::UnoType<decltype(xRet)>::get() ); + that->release(); + OSL_ASSERT( xRet.is() ); + if (! xRet.is()) + { + throw RuntimeException( "mapping UNO to C++ failed!" ); + } + } + return xRet; +} +// XInvocationAdapterFactory impl + +Reference< XInterface > FactoryImpl::createAdapter( + const Reference< script::XInvocation > & xReceiver, const Type & rType ) +{ + return createAdapter( xReceiver, Sequence< Type >( &rType, 1 ) ); +} + +// XServiceInfo + +OUString FactoryImpl::getImplementationName() +{ + return "com.sun.star.comp.stoc.InvocationAdapterFactory"; +} + +sal_Bool FactoryImpl::supportsService( const OUString & rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > FactoryImpl::getSupportedServiceNames() +{ + return { "com.sun.star.script.InvocationAdapterFactory" }; +} + +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +stoc_invocation_adapter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new stoc_invadp::FactoryImpl(context)); +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/stoc/source/invocation_adapterfactory/invocadapt.component b/stoc/source/invocation_adapterfactory/invocadapt.component new file mode 100644 index 000000000..ec1723e22 --- /dev/null +++ b/stoc/source/invocation_adapterfactory/invocadapt.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.stoc.InvocationAdapterFactory" + constructor="stoc_invocation_adapter_get_implementation" single-instance="true"> + <service name="com.sun.star.script.InvocationAdapterFactory"/> + </implementation> +</component> |