summaryrefslogtreecommitdiffstats
path: root/stoc/source
diff options
context:
space:
mode:
Diffstat (limited to 'stoc/source')
-rw-r--r--stoc/source/corereflection/base.hxx424
-rw-r--r--stoc/source/corereflection/crarray.cxx200
-rw-r--r--stoc/source/corereflection/crbase.cxx248
-rw-r--r--stoc/source/corereflection/crcomp.cxx358
-rw-r--r--stoc/source/corereflection/crefl.cxx379
-rw-r--r--stoc/source/corereflection/crenum.cxx206
-rw-r--r--stoc/source/corereflection/criface.cxx916
-rw-r--r--stoc/source/corereflection/lrucache.hxx209
-rw-r--r--stoc/source/corereflection/reflection.component28
-rw-r--r--stoc/source/defaultregistry/defaultregistry.cxx1193
-rw-r--r--stoc/source/implementationregistration/implreg.cxx1580
-rw-r--r--stoc/source/implementationregistration/mergekeys.cxx176
-rw-r--r--stoc/source/implementationregistration/mergekeys.hxx46
-rw-r--r--stoc/source/inspect/introspection.component28
-rw-r--r--stoc/source/inspect/introspection.cxx2420
-rw-r--r--stoc/source/invocation/invocation.component26
-rw-r--r--stoc/source/invocation/invocation.cxx1097
-rw-r--r--stoc/source/invocation_adapterfactory/iafactory.cxx882
-rw-r--r--stoc/source/invocation_adapterfactory/invocadapt.component26
-rw-r--r--stoc/source/javaloader/javaloader.component28
-rw-r--r--stoc/source/javaloader/javaloader.cxx571
-rw-r--r--stoc/source/javavm/interact.cxx107
-rw-r--r--stoc/source/javavm/interact.hxx67
-rw-r--r--stoc/source/javavm/javavm.component28
-rw-r--r--stoc/source/javavm/javavm.cxx1483
-rw-r--r--stoc/source/javavm/javavm.hxx147
-rw-r--r--stoc/source/javavm/jvmargs.cxx32
-rw-r--r--stoc/source/javavm/jvmargs.hxx58
-rw-r--r--stoc/source/loader/dllcomponentloader.cxx152
-rw-r--r--stoc/source/namingservice/namingservice.component26
-rw-r--r--stoc/source/namingservice/namingservice.cxx123
-rw-r--r--stoc/source/proxy_factory/proxyfac.component26
-rw-r--r--stoc/source/proxy_factory/proxyfac.cxx410
-rw-r--r--stoc/source/security/access_controller.cxx863
-rw-r--r--stoc/source/security/file_policy.cxx493
-rw-r--r--stoc/source/security/lru_cache.h210
-rw-r--r--stoc/source/security/permissions.cxx604
-rw-r--r--stoc/source/security/permissions.h85
-rw-r--r--stoc/source/servicemanager/servicemanager.cxx1476
-rw-r--r--stoc/source/simpleregistry/simpleregistry.cxx941
-rw-r--r--stoc/source/typeconv/convert.cxx870
-rw-r--r--stoc/source/uriproc/ExternalUriReferenceTranslator.cxx187
-rw-r--r--stoc/source/uriproc/UriReference.cxx183
-rw-r--r--stoc/source/uriproc/UriReference.hxx112
-rw-r--r--stoc/source/uriproc/UriReferenceFactory.cxx719
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx198
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx386
-rw-r--r--stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx119
48 files changed, 21146 insertions, 0 deletions
diff --git a/stoc/source/corereflection/base.hxx b/stoc/source/corereflection/base.hxx
new file mode 100644
index 000000000..16d42213d
--- /dev/null
+++ b/stoc/source/corereflection/base.hxx
@@ -0,0 +1,424 @@
+/* -*- 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 .
+ */
+// #define TEST_LIST_CLASSES
+
+#ifndef INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+#define INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <osl/mutex.hxx>
+#include <uno/mapping.hxx>
+#include <uno/dispatcher.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/component.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+
+#include "lrucache.hxx"
+
+#ifdef TEST_LIST_CLASSES
+#include <vector>
+#include <algorithm>
+#endif
+#include <unordered_map>
+#include <memory>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::reflection { class XIdlClass; }
+namespace com::sun::star::reflection { class XIdlField; }
+namespace com::sun::star::reflection { class XIdlMethod; }
+
+namespace stoc_corefl
+{
+
+#ifdef TEST_LIST_CLASSES
+extern std::vector<OUString> g_aClassNames;
+#endif
+
+
+::osl::Mutex & getMutexAccess();
+
+
+inline bool td_equals( typelib_TypeDescription * pTD, typelib_TypeDescriptionReference * pType )
+{
+ return (pTD->pWeakRef == pType ||
+ (pTD->pTypeName->length == pType->pTypeName->length &&
+ rtl_ustr_compare( pTD->pTypeName->buffer, pType->pTypeName->buffer ) == 0));
+}
+
+typedef std::unordered_map< OUString, css::uno::WeakReference< css::reflection::XIdlField > > OUString2Field;
+typedef std::unordered_map< OUString, css::uno::WeakReference< css::reflection::XIdlMethod > > OUString2Method;
+
+
+class IdlReflectionServiceImpl
+ : public ::cppu::OComponentHelper
+ , public css::reflection::XIdlReflection
+ , public css::container::XHierarchicalNameAccess
+ , public css::lang::XServiceInfo
+{
+ ::osl::Mutex _aComponentMutex;
+ css::uno::Reference< css::container::XHierarchicalNameAccess > _xTDMgr;
+
+ // caching
+ LRU_CacheAnyByOUString _aElements;
+
+ css::uno::Mapping _aCpp2Uno;
+ css::uno::Mapping _aUno2Cpp;
+
+ inline css::uno::Reference< css::reflection::XIdlClass > constructClass( typelib_TypeDescription * pTypeDescr );
+
+public:
+ /// @throws css::uno::RuntimeException
+ const css::uno::Mapping & getCpp2Uno();
+ /// @throws css::uno::RuntimeException
+ const css::uno::Mapping & getUno2Cpp();
+ /// @throws css::uno::RuntimeException
+ uno_Interface * mapToUno( const css::uno::Any & rObj, typelib_InterfaceTypeDescription * pTo );
+
+ // ctor/ dtor
+ explicit IdlReflectionServiceImpl( const css::uno::Reference< css::uno::XComponentContext > & xContext );
+ virtual ~IdlReflectionServiceImpl() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // some XComponent part from OComponentHelper
+ virtual void SAL_CALL dispose() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlReflection
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL forName( const OUString & rTypeName ) override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getType( const css::uno::Any & rObj ) override;
+
+ // XHierarchicalNameAccess
+ virtual css::uno::Any SAL_CALL getByHierarchicalName( const OUString & rName ) override;
+ virtual sal_Bool SAL_CALL hasByHierarchicalName( const OUString & rName ) override;
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::reflection::XIdlClass > forType( typelib_TypeDescription * pTypeDescr );
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::reflection::XIdlClass > forType( typelib_TypeDescriptionReference * pRef );
+};
+
+
+class IdlClassImpl
+ : public ::cppu::WeakImplHelper< css::reflection::XIdlClass >
+{
+ rtl::Reference<IdlReflectionServiceImpl>
+ m_xReflection;
+
+ OUString _aName;
+ css::uno::TypeClass _eTypeClass;
+
+ typelib_TypeDescription * _pTypeDescr;
+
+public:
+ typelib_TypeDescription * getTypeDescr() const
+ { return _pTypeDescr; }
+ IdlReflectionServiceImpl * getReflection() const
+ { return m_xReflection.get(); }
+
+ // Ctor
+ IdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr );
+ virtual ~IdlClassImpl() override;
+
+ // XIdlClassImpl default implementation
+ virtual css::uno::TypeClass SAL_CALL getTypeClass() override;
+ virtual OUString SAL_CALL getName() override;
+ virtual sal_Bool SAL_CALL equals( const css::uno::Reference< css::reflection::XIdlClass >& xType ) override;
+
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+
+ // def impl ????
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getClasses() override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getClass( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getInterfaces() override;
+
+ // structs, interfaces
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ // structs
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ // interfaces
+ virtual css::uno::Uik SAL_CALL getUik() override;
+ virtual css::uno::Reference< css::reflection::XIdlMethod > SAL_CALL getMethod( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlMethod > > SAL_CALL getMethods() override;
+ // array
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getComponentType() override;
+ virtual css::uno::Reference< css::reflection::XIdlArray > SAL_CALL getArray() override;
+};
+
+
+class InterfaceIdlClassImpl
+ : public IdlClassImpl
+{
+ typedef std::pair< OUString, typelib_TypeDescription * > MemberInit;
+
+ css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > _xSuperClasses;
+
+ std::unique_ptr<MemberInit[]> _pSortedMemberInit; // first methods, then attributes
+ OUString2Field _aName2Field;
+ OUString2Method _aName2Method;
+ sal_Int32 _nMethods;
+ sal_Int32 _nAttributes;
+
+ void initMembers();
+
+public:
+ typelib_InterfaceTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ InterfaceIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ , _nMethods( 0 )
+ , _nAttributes( 0 )
+ {}
+ virtual ~InterfaceIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ virtual css::uno::Uik SAL_CALL getUik() override;
+ virtual css::uno::Reference< css::reflection::XIdlMethod > SAL_CALL getMethod( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlMethod > > SAL_CALL getMethods() override;
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+};
+
+
+class CompoundIdlClassImpl
+ : public IdlClassImpl
+{
+ css::uno::Reference< css::reflection::XIdlClass >
+ _xSuperClass;
+ std::optional< css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > >
+ m_xFields;
+ OUString2Field _aName2Field;
+
+public:
+ typelib_CompoundTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_CompoundTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ CompoundIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+ virtual ~CompoundIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+};
+
+
+class ArrayIdlClassImpl
+ : public IdlClassImpl
+ , public css::reflection::XIdlArray
+{
+public:
+ typelib_IndirectTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_IndirectTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor
+ ArrayIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getComponentType() override;
+ virtual css::uno::Reference< css::reflection::XIdlArray > SAL_CALL getArray() override;
+
+ // XIdlArray
+ virtual void SAL_CALL realloc( css::uno::Any & rArray, sal_Int32 nLen ) override;
+ virtual sal_Int32 SAL_CALL getLen( const css::uno::Any & rArray ) override;
+ virtual css::uno::Any SAL_CALL get( const css::uno::Any & rArray, sal_Int32 nIndex ) override;
+ virtual void SAL_CALL set( css::uno::Any & rArray, sal_Int32 nIndex, const css::uno::Any & rNewValue ) override;
+};
+
+
+class EnumIdlClassImpl
+ : public IdlClassImpl
+{
+ std::optional< css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > > m_xFields;
+ OUString2Field _aName2Field;
+
+public:
+ typelib_EnumTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_EnumTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ EnumIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+ virtual ~EnumIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+};
+
+
+class IdlMemberImpl
+ : public ::cppu::WeakImplHelper< css::reflection::XIdlMember >
+{
+ rtl::Reference<IdlReflectionServiceImpl>
+ m_xReflection;
+ OUString _aName;
+
+ typelib_TypeDescription * _pTypeDescr;
+ typelib_TypeDescription * _pDeclTypeDescr;
+
+protected:
+ css::uno::Reference< css::reflection::XIdlClass > _xDeclClass;
+
+public:
+ IdlReflectionServiceImpl * getReflection() const
+ { return m_xReflection.get(); }
+ typelib_TypeDescription * getTypeDescr() const
+ { return _pTypeDescr; }
+ typelib_TypeDescription * getDeclTypeDescr() const
+ { return _pDeclTypeDescr; }
+
+ // ctor/ dtor
+ IdlMemberImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr );
+ virtual ~IdlMemberImpl() override;
+
+ // XIdlMember
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+};
+
+
+// coerces to type descr pTo else queries for it: the interface pointer is returned via rDest
+// ## type to XidlClass coercion possible
+inline bool extract(
+ const css::uno::Any & rObj, typelib_InterfaceTypeDescription * pTo,
+ css::uno::Reference< css::uno::XInterface > & rDest,
+ IdlReflectionServiceImpl * pRefl )
+{
+ rDest.clear();
+ if (nullptr != pTo)
+ {
+ if (! rObj.hasValue())
+ return true;
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_INTERFACE)
+ {
+ return ::uno_type_assignData(
+ &rDest, pTo->aBase.pWeakRef,
+ const_cast< void * >( rObj.getValue() ), rObj.getValueTypeRef(),
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+ else if (auto t = o3tl::tryAccess<css::uno::Type>(rObj))
+ {
+ rDest = pRefl->forType( t->getTypeLibType() );
+ return rDest.is();
+ }
+ }
+ return false;
+}
+
+inline bool coerce_assign(
+ void * pDest, typelib_TypeDescription * pTD, const css::uno::Any & rSource,
+ IdlReflectionServiceImpl * pRefl )
+{
+ if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ css::uno::Reference< css::uno::XInterface > xVal;
+ if (extract( rSource, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD), xVal, pRefl ))
+ {
+ if (*static_cast<css::uno::XInterface **>(pDest))
+ (*static_cast<css::uno::XInterface **>(pDest))->release();
+ *static_cast<css::uno::XInterface **>(pDest) = xVal.get();
+ if (*static_cast<css::uno::XInterface **>(pDest))
+ (*static_cast<css::uno::XInterface **>(pDest))->acquire();
+ return true;
+ }
+ return false;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ return uno_assignData(
+ pDest, pTD,
+ const_cast<css::uno::Any *>(&rSource), pTD,
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+ else
+ {
+ return uno_type_assignData(
+ pDest, pTD->pWeakRef,
+ const_cast<void *>(rSource.getValue()), rSource.getValueTypeRef(),
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+}
+
+}
+
+
+#endif // INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crarray.cxx b/stoc/source/corereflection/crarray.cxx
new file mode 100644
index 000000000..8a402c489
--- /dev/null
+++ b/stoc/source/corereflection/crarray.cxx
@@ -0,0 +1,200 @@
+/* -*- 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 <typelib/typedescription.h>
+#include <uno/data.h>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include "base.hxx"
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+// XInterface
+
+Any ArrayIdlClassImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface( rType, static_cast< XIdlArray * >( this ) ) );
+ return (aRet.hasValue() ? aRet : IdlClassImpl::queryInterface( rType ));
+}
+
+void ArrayIdlClassImpl::acquire() noexcept
+{
+ IdlClassImpl::acquire();
+}
+
+void ArrayIdlClassImpl::release() noexcept
+{
+ IdlClassImpl::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > ArrayIdlClassImpl::getTypes()
+{
+ static cppu::OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlArray>::get(),
+ IdlClassImpl::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > ArrayIdlClassImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlArray
+
+void ArrayIdlClassImpl::realloc( Any & rArray, sal_Int32 nLen )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+ }
+ if (nLen < 0)
+ {
+ throw IllegalArgumentException(
+ "negative length given!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 1 );
+ }
+
+ uno_Sequence ** ppSeq = const_cast<uno_Sequence **>(static_cast<uno_Sequence * const *>(rArray.getValue()));
+ uno_sequence_realloc( ppSeq, &getTypeDescr()->aBase,
+ nLen,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ rArray.pData = ppSeq;
+}
+
+sal_Int32 ArrayIdlClassImpl::getLen( const Any & rArray )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+ }
+
+ return (*static_cast<uno_Sequence * const *>(rArray.getValue()))->nElements;
+}
+
+Any ArrayIdlClassImpl::get( const Any & rArray, sal_Int32 nIndex )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+ }
+
+ uno_Sequence * pSeq = *static_cast<uno_Sequence * const *>(rArray.getValue());
+ if (pSeq->nElements <= nIndex)
+ {
+ throw ArrayIndexOutOfBoundsException(
+ "illegal index given, index " + OUString::number(nIndex) + " is < " + OUString::number(pSeq->nElements),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+ }
+
+ Any aRet;
+ typelib_TypeDescription * pElemTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElemTypeDescr, getTypeDescr()->pType );
+ uno_any_destruct( &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct( &aRet, &pSeq->elements[nIndex * pElemTypeDescr->nSize],
+ pElemTypeDescr,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+ return aRet;
+}
+
+
+void ArrayIdlClassImpl::set( Any & rArray, sal_Int32 nIndex, const Any & rNewValue )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+ }
+
+ uno_Sequence * pSeq = *static_cast<uno_Sequence * const *>(rArray.getValue());
+ if (pSeq->nElements <= nIndex)
+ {
+ throw ArrayIndexOutOfBoundsException(
+ "illegal index given, index " + OUString::number(nIndex) + " is < " + OUString::number(pSeq->nElements),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+ }
+
+ uno_Sequence ** ppSeq = const_cast<uno_Sequence **>(static_cast<uno_Sequence * const *>(rArray.getValue()));
+ uno_sequence_reference2One(
+ ppSeq, &getTypeDescr()->aBase,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ rArray.pData = ppSeq;
+ pSeq = *ppSeq;
+
+ typelib_TypeDescription * pElemTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElemTypeDescr, getTypeDescr()->pType );
+
+ if (! coerce_assign( &pSeq->elements[nIndex * pElemTypeDescr->nSize],
+ pElemTypeDescr, rNewValue, getReflection() ))
+ {
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+ throw IllegalArgumentException(
+ "sequence element is not assignable by given value!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 2 );
+ }
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+}
+
+// ArrayIdlClassImpl
+
+sal_Bool ArrayIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ return (xType.is() &&
+ (equals( xType ) ||
+ (xType->getTypeClass() == getTypeClass() && // must be sequence|array
+ getComponentType()->isAssignableFrom( xType->getComponentType() ))));
+}
+
+Reference< XIdlClass > ArrayIdlClassImpl::getComponentType()
+{
+ return getReflection()->forType( getTypeDescr()->pType );
+}
+
+Reference< XIdlArray > ArrayIdlClassImpl::getArray()
+{
+ return this;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crbase.cxx b/stoc/source/corereflection/crbase.cxx
new file mode 100644
index 000000000..75e802c96
--- /dev/null
+++ b/stoc/source/corereflection/crbase.cxx
@@ -0,0 +1,248 @@
+/* -*- 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 <uno/any2.h>
+
+#include "base.hxx"
+
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+#ifdef TEST_LIST_CLASSES
+ClassNameVector g_aClassNames;
+#endif
+
+
+::osl::Mutex & getMutexAccess()
+{
+ static osl::Mutex s_aMutex;
+
+ return s_aMutex;
+}
+
+
+IdlClassImpl::IdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : m_xReflection( pReflection )
+ , _aName( rName )
+ , _eTypeClass( static_cast<TypeClass>(eTypeClass) )
+ , _pTypeDescr( pTypeDescr )
+{
+ if (_pTypeDescr)
+ {
+ typelib_typedescription_acquire( _pTypeDescr );
+ if (! _pTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pTypeDescr );
+ }
+
+#ifdef TEST_LIST_CLASSES
+ ClassNameVector::const_iterator iFind( std::find( g_aClassNames.begin(), g_aClassNames.end(), _aName ) );
+ OSL_ENSURE( iFind == g_aClassNames.end(), "### idl class already exists!" );
+ g_aClassNames.insert(g_aClassNames.begin(), _aName);
+#endif
+}
+
+IdlClassImpl::~IdlClassImpl()
+{
+ if (_pTypeDescr)
+ typelib_typedescription_release( _pTypeDescr );
+ m_xReflection.clear();
+
+#ifdef TEST_LIST_CLASSES
+ ClassNameVector::iterator iFind( std::find( g_aClassNames.begin(), g_aClassNames.end(), _aName ) );
+ OSL_ENSURE( iFind != g_aClassNames.end(), "### idl class does not exist!" );
+ g_aClassNames.erase( iFind );
+#endif
+}
+
+// XIdlClassImpl default implementation
+
+TypeClass IdlClassImpl::getTypeClass()
+{
+ return _eTypeClass;
+}
+
+OUString IdlClassImpl::getName()
+{
+ return _aName;
+}
+
+sal_Bool IdlClassImpl::equals( const Reference< XIdlClass >& xType )
+{
+ return (xType.is() &&
+ (xType->getTypeClass() == _eTypeClass) && (xType->getName() == _aName));
+}
+
+const bool s_aAssignableFromTab[11][11] =
+{
+ /* from CH, BO, BY, SH, US, LO, UL, HY, UH, FL, DO */
+/* TypeClass_CHAR */ { true, false, false, false, false, false, false, false, false, false, false },
+/* TypeClass_BOOLEAN */ { false, true, false, false, false, false, false, false, false, false, false },
+/* TypeClass_BYTE */ { false, false, true, false, false, false, false, false, false, false, false },
+/* TypeClass_SHORT */ { false, false, true, true, true, false, false, false, false, false, false },
+/* TypeClass_UNSIGNED_SHORT */ { false, false, true, true, true, false, false, false, false, false, false },
+/* TypeClass_LONG */ { false, false, true, true, true, true, true, false, false, false, false },
+/* TypeClass_UNSIGNED_LONG */ { false, false, true, true, true, true, true, false, false, false, false },
+/* TypeClass_HYPER */ { false, false, true, true, true, true, true, true, true, false, false },
+/* TypeClass_UNSIGNED_HYPER */ { false, false, true, true, true, true, true, true, true, false, false },
+/* TypeClass_FLOAT */ { false, false, true, true, true, true, true, true, true, true, false },
+/* TypeClass_DOUBLE */ { false, false, true, true, true, true, true, true, true, true, true }
+};
+
+sal_Bool IdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ TypeClass eAssign = getTypeClass();
+ if (equals( xType ) || eAssign == TypeClass_ANY) // default shot
+ {
+ return true;
+ }
+ else
+ {
+ TypeClass eFrom = xType->getTypeClass();
+ if (eAssign > TypeClass_VOID && eAssign < TypeClass_STRING &&
+ eFrom > TypeClass_VOID && eFrom < TypeClass_STRING)
+ {
+ return s_aAssignableFromTab[static_cast<int>(eAssign)-1][static_cast<int>(eFrom)-1];
+ }
+ }
+ return false;
+}
+
+void IdlClassImpl::createObject( Any & rObj )
+{
+ rObj.clear();
+ uno_any_destruct( &rObj, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct( &rObj, nullptr, getTypeDescr(), nullptr );
+}
+
+// what TODO ????
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getClasses()
+{
+ OSL_FAIL( "### unexpected use!" );
+ return Sequence< Reference< XIdlClass > >();
+}
+
+Reference< XIdlClass > IdlClassImpl::getClass( const OUString & )
+{
+ OSL_FAIL( "### unexpected use!" );
+ return Reference< XIdlClass >();
+}
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getInterfaces()
+{
+// OSL_FAIL( "### unexpected use!" );
+ return Sequence< Reference< XIdlClass > >();
+}
+
+// structs, interfaces
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getSuperclasses()
+{
+ return Sequence< Reference< XIdlClass > >();
+}
+// structs
+
+Reference< XIdlField > IdlClassImpl::getField( const OUString & )
+{
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > IdlClassImpl::getFields()
+{
+ return Sequence< Reference< XIdlField > >();
+}
+// interfaces
+
+Uik IdlClassImpl::getUik()
+{
+ return Uik();
+}
+
+Reference< XIdlMethod > IdlClassImpl::getMethod( const OUString & )
+{
+ return Reference< XIdlMethod >();
+}
+
+Sequence< Reference< XIdlMethod > > IdlClassImpl::getMethods()
+{
+ return Sequence< Reference< XIdlMethod > >();
+}
+// array
+
+Reference< XIdlClass > IdlClassImpl::getComponentType()
+{
+ return Reference< XIdlClass >();
+}
+
+Reference< XIdlArray > IdlClassImpl::getArray()
+{
+ return Reference< XIdlArray >();
+}
+
+
+IdlMemberImpl::IdlMemberImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr,
+ typelib_TypeDescription * pDeclTypeDescr )
+ : m_xReflection( pReflection )
+ , _aName( rName )
+ , _pTypeDescr( pTypeDescr )
+ , _pDeclTypeDescr( pDeclTypeDescr )
+{
+ typelib_typedescription_acquire( _pTypeDescr );
+ if (! _pTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pTypeDescr );
+ typelib_typedescription_acquire( _pDeclTypeDescr );
+ if (! _pDeclTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pDeclTypeDescr );
+}
+
+IdlMemberImpl::~IdlMemberImpl()
+{
+ typelib_typedescription_release( _pDeclTypeDescr );
+ typelib_typedescription_release( _pTypeDescr );
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlMemberImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ Reference< XIdlClass > xDeclClass( getReflection()->forType( getDeclTypeDescr() ) );
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ _xDeclClass = xDeclClass;
+ }
+ return _xDeclClass;
+}
+
+OUString IdlMemberImpl::getName()
+{
+ return _aName;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crcomp.cxx b/stoc/source/corereflection/crcomp.cxx
new file mode 100644
index 000000000..51cf4a6f0
--- /dev/null
+++ b/stoc/source/corereflection/crcomp.cxx
@@ -0,0 +1,358 @@
+/* -*- 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/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <com/sun/star/reflection/XIdlField.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/uno/TypeClass.hpp>
+
+#include "base.hxx"
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+namespace {
+
+class IdlCompFieldImpl
+ : public IdlMemberImpl
+ , public XIdlField
+ , public XIdlField2
+{
+ sal_Int32 _nOffset;
+
+public:
+ IdlCompFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr,
+ sal_Int32 nOffset )
+ : IdlMemberImpl( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ , _nOffset( nOffset )
+ {}
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual Sequence< Type > SAL_CALL getTypes() override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+};
+
+}
+
+// XInterface
+
+Any IdlCompFieldImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface( rType,
+ static_cast< XIdlField * >( this ),
+ static_cast< XIdlField2 * >( this ) ) );
+ return (aRet.hasValue() ? aRet : IdlMemberImpl::queryInterface( rType ));
+}
+
+void IdlCompFieldImpl::acquire() noexcept
+{
+ IdlMemberImpl::acquire();
+}
+
+void IdlCompFieldImpl::release() noexcept
+{
+ IdlMemberImpl::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > IdlCompFieldImpl::getTypes()
+{
+ static cppu::OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlField2>::get(),
+ cppu::UnoType<XIdlField>::get(),
+ IdlMemberImpl::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > IdlCompFieldImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlCompFieldImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ typelib_CompoundTypeDescription * pTD =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(getDeclTypeDescr());
+ while (pTD)
+ {
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTD->ppTypeRefs;
+ for ( sal_Int32 nPos = pTD->nMembers; nPos--; )
+ {
+ if (td_equals( getTypeDescr(), ppTypeRefs[nPos] ))
+ {
+ _xDeclClass = getReflection()->forType( &pTD->aBase );
+ return _xDeclClass;
+ }
+ }
+ pTD = pTD->pBaseTypeDescription;
+ }
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlCompFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlCompFieldImpl::getType()
+{
+ return getReflection()->forType( getTypeDescr() );
+}
+
+FieldAccessMode IdlCompFieldImpl::getAccessMode()
+{
+ return FieldAccessMode_READWRITE;
+}
+
+Any IdlCompFieldImpl::get( const Any & rObj )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ Any aRet;
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct(
+ &aRet, const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ return aRet;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+void IdlCompFieldImpl::set( const Any & rObj, const Any & rValue )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ if (!coerce_assign( const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(), rValue, getReflection() ))
+ {
+ throw IllegalArgumentException(
+ "cannot assign value to destination",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 1 );
+ }
+ return;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+
+void IdlCompFieldImpl::set( Any & rObj, const Any & rValue )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ if (!coerce_assign( const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(), rValue, getReflection() ))
+ {
+ throw IllegalArgumentException(
+ "cannot assign to destination",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 1 );
+ }
+ return;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+
+CompoundIdlClassImpl::~CompoundIdlClassImpl()
+{
+}
+
+
+sal_Bool CompoundIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ if (xType.is())
+ {
+ TypeClass eTC = xType->getTypeClass();
+ if (eTC == TypeClass_STRUCT || eTC == TypeClass_EXCEPTION)
+ {
+ if (equals( xType ))
+ return true;
+ else
+ {
+ const Sequence< Reference< XIdlClass > > & rSeq = xType->getSuperclasses();
+ if (rSeq.hasElements())
+ {
+ OSL_ENSURE( rSeq.getLength() == 1, "### unexpected len of super classes!" );
+ return isAssignableFrom( rSeq[0] );
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Sequence< Reference< XIdlClass > > CompoundIdlClassImpl::getSuperclasses()
+{
+ if (! _xSuperClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xSuperClass.is())
+ {
+ typelib_CompoundTypeDescription * pCompTypeDescr = getTypeDescr()->pBaseTypeDescription;
+ if (pCompTypeDescr)
+ _xSuperClass = getReflection()->forType( &pCompTypeDescr->aBase );
+ }
+ }
+ if (_xSuperClass.is())
+ return Sequence< Reference< XIdlClass > >( &_xSuperClass, 1 );
+ else
+ return Sequence< Reference< XIdlClass > >();
+}
+
+Reference< XIdlField > CompoundIdlClassImpl::getField( const OUString & rName )
+{
+ if (! m_xFields)
+ getFields(); // init fields
+
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ return Reference< XIdlField >( (*iFind).second );
+ else
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > CompoundIdlClassImpl::getFields()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xFields)
+ {
+ sal_Int32 nAll = 0;
+ typelib_CompoundTypeDescription * pCompTypeDescr = getTypeDescr();
+ for ( ; pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ nAll += pCompTypeDescr->nMembers;
+
+ Sequence< Reference< XIdlField > > aFields( nAll );
+ Reference< XIdlField > * pSeq = aFields.getArray();
+
+ for ( pCompTypeDescr = getTypeDescr(); pCompTypeDescr;
+ pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
+ rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
+ sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
+
+ for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, ppTypeRefs[nPos] );
+ OSL_ENSURE( pTD, "### cannot get field in struct!" );
+ if (pTD)
+ {
+ OUString aName( ppNames[nPos] );
+ _aName2Field[aName] = pSeq[--nAll] = new IdlCompFieldImpl(
+ getReflection(), aName, pTD, IdlClassImpl::getTypeDescr(), pMemberOffsets[nPos] );
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ }
+ }
+
+ m_xFields = std::move( aFields );
+ }
+ return *m_xFields;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crefl.cxx b/stoc/source/corereflection/crefl.cxx
new file mode 100644
index 000000000..af1854e7e
--- /dev/null
+++ b/stoc/source/corereflection/crefl.cxx
@@ -0,0 +1,379 @@
+/* -*- 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/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/reflection/XConstantTypeDescription.hpp>
+#include <com/sun/star/reflection/XTypeDescription.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <o3tl/any.hxx>
+#include <uno/lbnames.h>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::reflection;
+using namespace cppu;
+using namespace osl;
+
+
+#include "base.hxx"
+
+
+namespace stoc_corefl
+{
+
+IdlReflectionServiceImpl::IdlReflectionServiceImpl(
+ const Reference< XComponentContext > & xContext )
+ : OComponentHelper( _aComponentMutex )
+{
+ xContext->getValueByName(
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager" ) >>= _xTDMgr;
+ OSL_ENSURE( _xTDMgr.is(), "### cannot get singleton \"TypeDescriptionManager\" from context!" );
+}
+
+IdlReflectionServiceImpl::~IdlReflectionServiceImpl() {}
+
+// XInterface
+
+Any IdlReflectionServiceImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface(
+ rType,
+ static_cast< XIdlReflection * >( this ),
+ static_cast< XHierarchicalNameAccess * >( this ),
+ static_cast< XServiceInfo * >( this ) ) );
+
+ return (aRet.hasValue() ? aRet : OComponentHelper::queryInterface( rType ));
+}
+
+void IdlReflectionServiceImpl::acquire() noexcept
+{
+ OComponentHelper::acquire();
+}
+
+void IdlReflectionServiceImpl::release() noexcept
+{
+ OComponentHelper::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > IdlReflectionServiceImpl::getTypes()
+{
+ static OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlReflection>::get(),
+ cppu::UnoType<XHierarchicalNameAccess>::get(),
+ cppu::UnoType<XServiceInfo>::get(),
+ OComponentHelper::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > IdlReflectionServiceImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XComponent
+
+void IdlReflectionServiceImpl::dispose()
+{
+ OComponentHelper::dispose();
+
+ MutexGuard aGuard( _aComponentMutex );
+ _aElements.clear();
+#ifdef TEST_LIST_CLASSES
+ OSL_ENSURE( g_aClassNames.empty(), "### idl classes still alive!" );
+ for (auto const& className : g_aClassNames)
+ {
+ OUString aName(className);
+ }
+#endif
+}
+
+// XServiceInfo
+
+OUString IdlReflectionServiceImpl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.CoreReflection";
+}
+
+sal_Bool IdlReflectionServiceImpl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > IdlReflectionServiceImpl::getSupportedServiceNames()
+{
+ Sequence< OUString > seqNames { "com.sun.star.reflection.CoreReflection" };
+ return seqNames;
+}
+
+// XIdlReflection
+
+Reference< XIdlClass > IdlReflectionServiceImpl::getType( const Any & rObj )
+{
+ return (rObj.hasValue() ? forType( rObj.getValueTypeRef() ) : Reference< XIdlClass >());
+}
+
+
+inline Reference< XIdlClass > IdlReflectionServiceImpl::constructClass(
+ typelib_TypeDescription * pTypeDescr )
+{
+ OSL_ENSURE( pTypeDescr->eTypeClass != typelib_TypeClass_TYPEDEF, "### unexpected typedef!" );
+
+ switch (pTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_ANY:
+ return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_ENUM:
+ return new EnumIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ return new CompoundIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_SEQUENCE:
+ return new ArrayIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_INTERFACE:
+ return new InterfaceIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_TYPE:
+ return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ default:
+ SAL_INFO("stoc", "corereflection type unsupported: " << pTypeDescr->pTypeName);
+ return Reference< XIdlClass >();
+ }
+}
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forName( const OUString & rTypeName )
+{
+ Reference< XIdlClass > xRet;
+ Any aAny( _aElements.getValue( rTypeName ) );
+
+ if (aAny.hasValue())
+ {
+ aAny >>= xRet;
+ }
+ else
+ {
+ // try to get _type_ by name
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescription_getByName( &pTD, rTypeName.pData );
+ if (pTD)
+ {
+ xRet = constructClass( pTD );
+ if (xRet.is())
+ _aElements.setValue( rTypeName, Any( xRet ) ); // update
+ typelib_typedescription_release( pTD );
+ }
+ }
+
+ return xRet;
+}
+
+// XHierarchicalNameAccess
+
+Any IdlReflectionServiceImpl::getByHierarchicalName( const OUString & rName )
+{
+ Any aRet( _aElements.getValue( rName ) );
+ if (! aRet.hasValue())
+ {
+ aRet = _xTDMgr->getByHierarchicalName( rName );
+ if (aRet.getValueTypeClass() == TypeClass_INTERFACE)
+ {
+ // type retrieved from tdmgr
+ OSL_ASSERT( (*o3tl::forceAccess<Reference<XInterface>>(aRet))->queryInterface(
+ cppu::UnoType<XTypeDescription>::get()).hasValue() );
+
+ css::uno::Reference< css::reflection::XConstantTypeDescription >
+ ctd;
+ if (aRet >>= ctd)
+ {
+ aRet = ctd->getConstantValue();
+ }
+ else
+ {
+ // if you are interested in a type then CALL forName()!!!
+ // this way is NOT recommended for types, because this method looks for constants first
+
+ // if td manager found some type, it will be in the cache (hopefully... we just got it)
+ // so the second retrieving via c typelib callback chain should succeed...
+
+ // try to get _type_ by name
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescription_getByName( &pTD, rName.pData );
+
+ aRet.clear(); // kick XTypeDescription interface
+
+ if (pTD)
+ {
+ Reference< XIdlClass > xIdlClass( constructClass( pTD ) );
+ aRet.setValue( &xIdlClass, cppu::UnoType<XIdlClass>::get());
+ typelib_typedescription_release( pTD );
+ }
+ }
+ }
+ // else is enum member(?)
+
+ // update
+ if (!aRet.hasValue())
+ throw container::NoSuchElementException( rName );
+
+ _aElements.setValue( rName, aRet );
+ }
+ return aRet;
+}
+
+sal_Bool IdlReflectionServiceImpl::hasByHierarchicalName( const OUString & rName )
+{
+ try
+ {
+ return getByHierarchicalName( rName ).hasValue();
+ }
+ catch (container::NoSuchElementException &)
+ {
+ }
+ return false;
+}
+
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescription * pTypeDescr )
+{
+ Reference< XIdlClass > xRet;
+ OUString aName( pTypeDescr->pTypeName );
+ Any aAny( _aElements.getValue( aName ) );
+
+ if (aAny.hasValue())
+ {
+ aAny >>= xRet;
+ }
+ else
+ {
+ xRet = constructClass( pTypeDescr );
+ if (xRet.is())
+ _aElements.setValue( aName, Any( xRet ) ); // update
+ }
+
+ return xRet;
+}
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescriptionReference * pRef )
+{
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pRef );
+ if (pTD)
+ {
+ Reference< XIdlClass > xRet = forType( pTD );
+ TYPELIB_DANGER_RELEASE( pTD );
+ return xRet;
+ }
+ throw RuntimeException(
+ "IdlReflectionServiceImpl::forType() failed!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+}
+
+
+const Mapping & IdlReflectionServiceImpl::getCpp2Uno()
+{
+ if (! _aCpp2Uno.is())
+ {
+ MutexGuard aGuard( getMutexAccess() );
+ if (! _aCpp2Uno.is())
+ {
+ _aCpp2Uno = Mapping( CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO );
+ OSL_ENSURE( _aCpp2Uno.is(), "### cannot get c++ to uno mapping!" );
+ if (! _aCpp2Uno.is())
+ {
+ throw RuntimeException(
+ "cannot get c++ to uno mapping!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+ }
+ }
+ }
+ return _aCpp2Uno;
+}
+
+const Mapping & IdlReflectionServiceImpl::getUno2Cpp()
+{
+ if (! _aUno2Cpp.is())
+ {
+ MutexGuard aGuard( getMutexAccess() );
+ if (! _aUno2Cpp.is())
+ {
+ _aUno2Cpp = Mapping( UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME );
+ OSL_ENSURE( _aUno2Cpp.is(), "### cannot get uno to c++ mapping!" );
+ if (! _aUno2Cpp.is())
+ {
+ throw RuntimeException(
+ "cannot get uno to c++ mapping!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+ }
+ }
+ }
+ return _aUno2Cpp;
+}
+
+uno_Interface * IdlReflectionServiceImpl::mapToUno(
+ const Any & rObj, typelib_InterfaceTypeDescription * pTo )
+{
+ Reference< XInterface > xObj;
+ if (extract( rObj, pTo, xObj, this ))
+ return static_cast<uno_Interface *>(getCpp2Uno().mapInterface( xObj.get(), pTo ));
+
+ throw RuntimeException(
+ "illegal object given!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+}
+
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_CoreReflection_get_implementation(
+ css::uno::XComponentContext * context,
+ css::uno::Sequence<css::uno::Any> const & arguments)
+{
+ SAL_WARN_IF(
+ arguments.hasElements(), "stoc", "unexpected singleton arguments");
+ return cppu::acquire(new stoc_corefl::IdlReflectionServiceImpl(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crenum.cxx b/stoc/source/corereflection/crenum.cxx
new file mode 100644
index 000000000..dae3449d3
--- /dev/null
+++ b/stoc/source/corereflection/crenum.cxx
@@ -0,0 +1,206 @@
+/* -*- 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 "base.hxx"
+
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <com/sun/star/reflection/XIdlField2.hpp>
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+namespace {
+
+class IdlEnumFieldImpl
+ : public IdlMemberImpl
+ , public XIdlField
+ , public XIdlField2
+{
+ sal_Int32 _nValue;
+
+public:
+ IdlEnumFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, sal_Int32 nValue )
+ : IdlMemberImpl( pReflection, rName, pTypeDescr, pTypeDescr )
+ , _nValue( nValue )
+ {}
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual Sequence< Type > SAL_CALL getTypes() override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+};
+
+}
+
+// XInterface
+
+Any IdlEnumFieldImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface( rType,
+ static_cast< XIdlField * >( this ),
+ static_cast< XIdlField2 * >( this ) ) );
+ return (aRet.hasValue() ? aRet : IdlMemberImpl::queryInterface( rType ));
+}
+
+void IdlEnumFieldImpl::acquire() noexcept
+{
+ IdlMemberImpl::acquire();
+}
+
+void IdlEnumFieldImpl::release() noexcept
+{
+ IdlMemberImpl::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > IdlEnumFieldImpl::getTypes()
+{
+ static cppu::OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlField2>::get(),
+ cppu::UnoType<XIdlField>::get(),
+ IdlMemberImpl::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > IdlEnumFieldImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlEnumFieldImpl::getDeclaringClass()
+{
+ return IdlMemberImpl::getDeclaringClass();
+}
+
+OUString IdlEnumFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlEnumFieldImpl::getType()
+{
+ return getDeclaringClass();
+}
+
+FieldAccessMode IdlEnumFieldImpl::getAccessMode()
+{
+ return FieldAccessMode_READONLY;
+}
+
+Any IdlEnumFieldImpl::get( const Any & )
+{
+ return Any( &_nValue, getTypeDescr() );
+}
+
+void IdlEnumFieldImpl::set( const Any &, const Any & )
+{
+ throw IllegalAccessException(
+ "cannot set enum field, it is constant",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+}
+
+void IdlEnumFieldImpl::set( Any &, const Any & )
+{
+ throw IllegalAccessException(
+ "cannot set enum field, it is constant",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+}
+
+
+EnumIdlClassImpl::~EnumIdlClassImpl()
+{
+}
+
+// IdlClassImpl modifications
+
+Reference< XIdlField > EnumIdlClassImpl::getField( const OUString & rName )
+{
+ if (! m_xFields)
+ getFields(); // init members
+
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ return (*iFind).second;
+ else
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > EnumIdlClassImpl::getFields()
+{
+ if (! m_xFields)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xFields)
+ {
+ sal_Int32 nFields = getTypeDescr()->nEnumValues;
+ Sequence< Reference< XIdlField > > aFields( nFields );
+ Reference< XIdlField > * pSeq = aFields.getArray();
+
+ while (nFields--)
+ {
+ OUString aName( getTypeDescr()->ppEnumNames[nFields] );
+ _aName2Field[aName] = pSeq[nFields] = new IdlEnumFieldImpl(
+ getReflection(), aName, IdlClassImpl::getTypeDescr(), getTypeDescr()->pEnumValues[nFields] );
+ }
+
+ m_xFields = std::move( aFields );
+ }
+ }
+ return *m_xFields;
+}
+
+void EnumIdlClassImpl::createObject( Any & rObj )
+{
+ sal_Int32 eVal =
+ reinterpret_cast<typelib_EnumTypeDescription *>(IdlClassImpl::getTypeDescr())->nDefaultEnumValue;
+ rObj.setValue( &eVal, IdlClassImpl::getTypeDescr() );
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/criface.cxx b/stoc/source/corereflection/criface.cxx
new file mode 100644
index 000000000..88dcc29ff
--- /dev/null
+++ b/stoc/source/corereflection/criface.cxx
@@ -0,0 +1,916 @@
+/* -*- 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 <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <limits>
+
+#ifdef SAL_UNX
+#include <sal/alloca.h>
+#endif
+#include <o3tl/any.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+
+#include "base.hxx"
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace {
+
+std::size_t multipleOf16(std::size_t n) {
+ assert(n <= std::numeric_limits<std::size_t>::max() - 15);
+ return (n + 15) & ~std::size_t(15);
+}
+
+}
+
+namespace stoc_corefl
+{
+
+namespace {
+
+class IdlAttributeFieldImpl
+ : public IdlMemberImpl
+ , public XIdlField
+ , public XIdlField2
+{
+public:
+ typelib_InterfaceAttributeTypeDescription * getAttributeTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(getTypeDescr()); }
+
+ IdlAttributeFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr )
+ : IdlMemberImpl( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ {}
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual Sequence< Type > SAL_CALL getTypes() override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+
+private:
+ void checkException(
+ uno_Any * exception, Reference< XInterface > const & context) const;
+};
+
+}
+
+// XInterface
+
+Any IdlAttributeFieldImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface( rType,
+ static_cast< XIdlField * >( this ),
+ static_cast< XIdlField2 * >( this ) ) );
+ return (aRet.hasValue() ? aRet : IdlMemberImpl::queryInterface( rType ));
+}
+
+void IdlAttributeFieldImpl::acquire() noexcept
+{
+ IdlMemberImpl::acquire();
+}
+
+void IdlAttributeFieldImpl::release() noexcept
+{
+ IdlMemberImpl::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > IdlAttributeFieldImpl::getTypes()
+{
+ static cppu::OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlField2>::get(),
+ cppu::UnoType<XIdlField>::get(),
+ IdlMemberImpl::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > IdlAttributeFieldImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlAttributeFieldImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ OUString aName(getAttributeTypeDescr()->aBase.aBase.pTypeName);
+ sal_Int32 i = aName.indexOf(':');
+ OSL_ASSERT(i >= 0);
+ _xDeclClass = getReflection()->forName(aName.copy(0, i));
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlAttributeFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlAttributeFieldImpl::getType()
+{
+ return getReflection()->forType(
+ getAttributeTypeDescr()->pAttributeTypeRef );
+}
+
+FieldAccessMode IdlAttributeFieldImpl::getAccessMode()
+{
+ return (getAttributeTypeDescr()->bReadOnly
+ ? FieldAccessMode_READONLY : FieldAccessMode_READWRITE);
+}
+
+Any IdlAttributeFieldImpl::get( const Any & rObj )
+{
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ TypeDescription aTD( getAttributeTypeDescr()->pAttributeTypeRef );
+ typelib_TypeDescription * pTD = aTD.get();
+
+ uno_Any aExc;
+ uno_Any * pExc = &aExc;
+ void * pReturn = alloca( pTD->nSize );
+
+ (*pUnoI->pDispatcher)( pUnoI, getTypeDescr(), pReturn, nullptr, &pExc );
+ (*pUnoI->release)( pUnoI );
+
+ checkException(pExc, *o3tl::doAccess<Reference<XInterface>>(rObj));
+ Any aRet;
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert( &aRet, pReturn, pTD, getReflection()->getUno2Cpp().get() );
+ uno_destructData( pReturn, pTD, nullptr );
+ return aRet;
+ }
+ throw IllegalArgumentException(
+ "illegal object given!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+void IdlAttributeFieldImpl::set( Any & rObj, const Any & rValue )
+{
+ if (getAttributeTypeDescr()->bReadOnly)
+ {
+ throw IllegalAccessException(
+ "cannot set readonly attribute!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)) );
+ }
+
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ TypeDescription aTD( getAttributeTypeDescr()->pAttributeTypeRef );
+ typelib_TypeDescription * pTD = aTD.get();
+
+ // construct uno value to be set
+ void * pArgs[1];
+ void * pArg = pArgs[0] = alloca( pTD->nSize );
+
+ bool bAssign;
+ if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ uno_copyAndConvertData( pArg, const_cast< Any * >(&rValue),
+ pTD, getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (typelib_typedescriptionreference_equals( rValue.getValueTypeRef(), pTD->pWeakRef ))
+ {
+ uno_copyAndConvertData( pArg, const_cast< void * >(rValue.getValue()),
+ pTD, getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ Reference< XInterface > xObj;
+ bAssign = extract(
+ rValue, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD), xObj,
+ getReflection() );
+ if (bAssign)
+ {
+ *static_cast<void **>(pArg) = getReflection()->getCpp2Uno().mapInterface(
+ xObj.get(), reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+ }
+ }
+ else
+ {
+ typelib_TypeDescription * pValueTD = nullptr;
+ TYPELIB_DANGER_GET( &pValueTD, rValue.getValueTypeRef() );
+ // construct temp uno val to do proper assignment: todo opt
+ void * pTemp = alloca( pValueTD->nSize );
+ uno_copyAndConvertData(
+ pTemp, const_cast<void *>(rValue.getValue()), pValueTD, getReflection()->getCpp2Uno().get() );
+ uno_constructData(
+ pArg, pTD );
+ // assignment does simple conversion
+ bAssign = uno_assignData(
+ pArg, pTD, pTemp, pValueTD, nullptr, nullptr, nullptr );
+ uno_destructData(
+ pTemp, pValueTD, nullptr );
+ TYPELIB_DANGER_RELEASE( pValueTD );
+ }
+
+ if (bAssign)
+ {
+ uno_Any aExc;
+ uno_Any * pExc = &aExc;
+ (*pUnoI->pDispatcher)( pUnoI, getTypeDescr(), nullptr, pArgs, &pExc );
+ (*pUnoI->release)( pUnoI );
+
+ uno_destructData( pArg, pTD, nullptr );
+ checkException(pExc, *o3tl::doAccess<Reference<XInterface>>(rObj));
+ return;
+ }
+ (*pUnoI->release)( pUnoI );
+
+ throw IllegalArgumentException(
+ "illegal value given!",
+ *o3tl::doAccess<Reference<XInterface>>(rObj), 1 );
+ }
+ throw IllegalArgumentException(
+ "illegal destination object given!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+void IdlAttributeFieldImpl::set( const Any & rObj, const Any & rValue )
+{
+ IdlAttributeFieldImpl::set( const_cast< Any & >( rObj ), rValue );
+}
+
+void IdlAttributeFieldImpl::checkException(
+ uno_Any * exception, Reference< XInterface > const & context) const
+{
+ if (exception == nullptr)
+ return;
+
+ Any e;
+ uno_any_destruct(&e, reinterpret_cast< uno_ReleaseFunc >(cpp_release));
+ uno_type_any_constructAndConvert(
+ &e, exception->pData, exception->pType,
+ getReflection()->getUno2Cpp().get());
+ uno_any_destruct(exception, nullptr);
+ if (!e.isExtractableTo(
+ cppu::UnoType<RuntimeException>::get()))
+ {
+ throw WrappedTargetRuntimeException(
+ "non-RuntimeException occurred when accessing an"
+ " interface type attribute",
+ context, e);
+ }
+ cppu::throwException(e);
+}
+
+namespace {
+
+class IdlInterfaceMethodImpl
+ : public IdlMemberImpl
+ , public XIdlMethod
+{
+ std::optional<Sequence< Reference< XIdlClass > >> m_xExceptionTypes;
+ std::optional<Sequence< Reference< XIdlClass > >> m_xParamTypes;
+ std::optional<Sequence< ParamInfo >> m_xParamInfos;
+
+public:
+ typelib_InterfaceMethodTypeDescription * getMethodTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(getTypeDescr()); }
+
+ IdlInterfaceMethodImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr )
+ : IdlMemberImpl( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ {}
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual Sequence< Type > SAL_CALL getTypes() override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlMethod
+ virtual Reference< XIdlClass > SAL_CALL getReturnType() override;
+ virtual Sequence< Reference< XIdlClass > > SAL_CALL getParameterTypes() override;
+ virtual Sequence< ParamInfo > SAL_CALL getParameterInfos() override;
+ virtual Sequence< Reference< XIdlClass > > SAL_CALL getExceptionTypes() override;
+ virtual MethodMode SAL_CALL getMode() override;
+ virtual Any SAL_CALL invoke( const Any & rObj, Sequence< Any > & rArgs ) override;
+};
+
+}
+
+// XInterface
+
+Any IdlInterfaceMethodImpl::queryInterface( const Type & rType )
+{
+ Any aRet( ::cppu::queryInterface( rType, static_cast< XIdlMethod * >( this ) ) );
+ return (aRet.hasValue() ? aRet : IdlMemberImpl::queryInterface( rType ));
+}
+
+void IdlInterfaceMethodImpl::acquire() noexcept
+{
+ IdlMemberImpl::acquire();
+}
+
+void IdlInterfaceMethodImpl::release() noexcept
+{
+ IdlMemberImpl::release();
+}
+
+// XTypeProvider
+
+Sequence< Type > IdlInterfaceMethodImpl::getTypes()
+{
+ static cppu::OTypeCollection s_aTypes(
+ cppu::UnoType<XIdlMethod>::get(),
+ IdlMemberImpl::getTypes() );
+
+ return s_aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > IdlInterfaceMethodImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlInterfaceMethodImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ OUString aName(getMethodTypeDescr()->aBase.aBase.pTypeName);
+ sal_Int32 i = aName.indexOf(':');
+ OSL_ASSERT(i >= 0);
+ _xDeclClass = getReflection()->forName(aName.copy(0, i));
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlInterfaceMethodImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlMethod
+
+Reference< XIdlClass > SAL_CALL IdlInterfaceMethodImpl::getReturnType()
+{
+ return getReflection()->forType( getMethodTypeDescr()->pReturnTypeRef );
+}
+
+Sequence< Reference< XIdlClass > > IdlInterfaceMethodImpl::getExceptionTypes()
+{
+ if (! m_xExceptionTypes)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xExceptionTypes)
+ {
+ sal_Int32 nExc = getMethodTypeDescr()->nExceptions;
+ Sequence< Reference< XIdlClass > > aTempExceptionTypes( nExc );
+ Reference< XIdlClass > * pExceptionTypes = aTempExceptionTypes.getArray();
+
+ typelib_TypeDescriptionReference ** ppExc =
+ getMethodTypeDescr()->ppExceptions;
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nExc--)
+ pExceptionTypes[nExc] = pRefl->forType( ppExc[nExc] );
+
+ m_xExceptionTypes = std::move(aTempExceptionTypes);
+ }
+ }
+ return *m_xExceptionTypes;
+}
+
+Sequence< Reference< XIdlClass > > IdlInterfaceMethodImpl::getParameterTypes()
+{
+ if (! m_xParamTypes)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xParamTypes)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ Sequence< Reference< XIdlClass > > aTempParamTypes( nParams );
+ Reference< XIdlClass > * pParamTypes = aTempParamTypes.getArray();
+
+ typelib_MethodParameter * pTypelibParams =
+ getMethodTypeDescr()->pParams;
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nParams--)
+ pParamTypes[nParams] = pRefl->forType( pTypelibParams[nParams].pTypeRef );
+
+ m_xParamTypes = std::move(aTempParamTypes);
+ }
+ }
+ return *m_xParamTypes;
+}
+
+Sequence< ParamInfo > IdlInterfaceMethodImpl::getParameterInfos()
+{
+ if (! m_xParamInfos)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xParamInfos)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ Sequence< ParamInfo > aTempParamInfos( nParams );
+ ParamInfo * pParamInfos = aTempParamInfos.getArray();
+
+ typelib_MethodParameter * pTypelibParams =
+ getMethodTypeDescr()->pParams;
+
+ if (m_xParamTypes) // use param types
+ {
+ const Reference< XIdlClass > * pParamTypes = m_xParamTypes->getConstArray();
+
+ while (nParams--)
+ {
+ const typelib_MethodParameter & rParam = pTypelibParams[nParams];
+ ParamInfo & rInfo = pParamInfos[nParams];
+ rInfo.aName = rParam.pName;
+ if (rParam.bIn)
+ rInfo.aMode = (rParam.bOut ? ParamMode_INOUT : ParamMode_IN);
+ else
+ rInfo.aMode = ParamMode_OUT;
+ rInfo.aType = pParamTypes[nParams];
+ }
+ }
+ else // make also param types sequence if not already initialized
+ {
+ Sequence< Reference< XIdlClass > > aTempParamTypes( nParams );
+ Reference< XIdlClass > * pParamTypes = aTempParamTypes.getArray();
+
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nParams--)
+ {
+ const typelib_MethodParameter & rParam = pTypelibParams[nParams];
+ ParamInfo & rInfo = pParamInfos[nParams];
+ rInfo.aName = rParam.pName;
+ if (rParam.bIn)
+ rInfo.aMode = (rParam.bOut ? ParamMode_INOUT : ParamMode_IN);
+ else
+ rInfo.aMode = ParamMode_OUT;
+ rInfo.aType = pParamTypes[nParams] = pRefl->forType( rParam.pTypeRef );
+ }
+
+ m_xParamTypes = std::move(aTempParamTypes);
+ }
+
+ m_xParamInfos = std::move(aTempParamInfos);
+ }
+ }
+ return *m_xParamInfos;
+}
+
+MethodMode SAL_CALL IdlInterfaceMethodImpl::getMode()
+{
+ return
+ getMethodTypeDescr()->bOneWay ? MethodMode_ONEWAY : MethodMode_TWOWAY;
+}
+
+Any SAL_CALL IdlInterfaceMethodImpl::invoke( const Any & rObj, Sequence< Any > & rArgs )
+{
+ if (auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
+ rObj))
+ {
+ // acquire()/ release()
+ if (rtl_ustr_ascii_compare( getTypeDescr()->pTypeName->buffer,
+ "com.sun.star.uno.XInterface::acquire" ) == 0)
+ {
+ (*ifc)->acquire();
+ return Any();
+ }
+ else if (rtl_ustr_ascii_compare( getTypeDescr()->pTypeName->buffer,
+ "com.sun.star.uno.XInterface::release" ) == 0)
+ {
+ (*ifc)->release();
+ return Any();
+ }
+ }
+
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ if (rArgs.getLength() != nParams)
+ {
+ (*pUnoI->release)( pUnoI );
+ throw IllegalArgumentException(
+ "expected " + OUString::number(nParams) +
+ " arguments, got " + OUString::number(rArgs.getLength()),
+ *o3tl::doAccess<Reference<XInterface>>(rObj), 1 );
+ }
+
+ Any * pCppArgs = rArgs.getArray();
+ typelib_MethodParameter * pParams = getMethodTypeDescr()->pParams;
+ typelib_TypeDescription * pReturnType = nullptr;
+ TYPELIB_DANGER_GET(
+ &pReturnType, getMethodTypeDescr()->pReturnTypeRef );
+
+ // C/C++ ABIs typically assume that structs are padded at the end, and
+ // that those padding bytes may be written to (e.g., to write into the
+ // end of a "short" struct by writing the full contents of a "long"
+ // register); so create enough space here (assuming that no ABI requires
+ // padding larger than 16 byte boundaries):
+ void * pUnoReturn = (pReturnType->nSize == 0) ? nullptr : alloca( multipleOf16(pReturnType->nSize) );
+ void ** ppUnoArgs = static_cast<void **>(alloca( sizeof(void *) * nParams *2 ));
+ typelib_TypeDescription ** ppParamTypes = reinterpret_cast<typelib_TypeDescription **>(ppUnoArgs + nParams);
+
+ // convert arguments
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ ppParamTypes[nPos] = nullptr;
+ TYPELIB_DANGER_GET( ppParamTypes + nPos, pParams[nPos].pTypeRef );
+ typelib_TypeDescription * pTD = ppParamTypes[nPos];
+
+ ppUnoArgs[nPos] = alloca( pTD->nSize );
+ if (pParams[nPos].bIn)
+ {
+ bool bAssign;
+ if (typelib_typedescriptionreference_equals(
+ pCppArgs[nPos].getValueTypeRef(), pTD->pWeakRef ))
+ {
+ uno_type_copyAndConvertData(
+ ppUnoArgs[nPos], const_cast<void *>(pCppArgs[nPos].getValue()),
+ pCppArgs[nPos].getValueTypeRef(), getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ uno_type_any_constructAndConvert(
+ static_cast<uno_Any *>(ppUnoArgs[nPos]), const_cast<void *>(pCppArgs[nPos].getValue()),
+ pCppArgs[nPos].getValueTypeRef(), getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ Reference< XInterface > xDest;
+ bAssign = extract(
+ pCppArgs[nPos], reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD),
+ xDest, getReflection() );
+ if (bAssign)
+ {
+ *static_cast<void **>(ppUnoArgs[nPos]) = getReflection()->getCpp2Uno().mapInterface(
+ xDest.get(), reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+ }
+ }
+ else
+ {
+ typelib_TypeDescription * pValueTD = nullptr;
+ TYPELIB_DANGER_GET( &pValueTD, pCppArgs[nPos].getValueTypeRef() );
+ // construct temp uno val to do proper assignment: todo opt
+ void * pTemp = alloca( pValueTD->nSize );
+ uno_copyAndConvertData(
+ pTemp, const_cast<void *>(pCppArgs[nPos].getValue()), pValueTD,
+ getReflection()->getCpp2Uno().get() );
+ uno_constructData(
+ ppUnoArgs[nPos], pTD );
+ // assignment does simple conversion
+ bAssign = uno_assignData(
+ ppUnoArgs[nPos], pTD, pTemp, pValueTD, nullptr, nullptr, nullptr );
+ uno_destructData(
+ pTemp, pValueTD, nullptr );
+ TYPELIB_DANGER_RELEASE( pValueTD );
+ }
+
+ if (! bAssign)
+ {
+ IllegalArgumentException aExc(
+ "cannot coerce argument type during corereflection call:"
+ "\narg no.: " + OUString::number(nPos)
+ + " expected: \"" + OUString::unacquired(&pTD->pTypeName)
+ + "\" actual: \"" + OUString::unacquired(&pCppArgs[nPos].getValueTypeRef()->pTypeName)
+ + "\"",
+ *o3tl::doAccess<Reference<XInterface>>(rObj), static_cast<sal_Int16>(nPos) );
+
+ // cleanup
+ while (nPos--)
+ {
+ if (pParams[nPos].bIn)
+ uno_destructData( ppUnoArgs[nPos], ppParamTypes[nPos], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nPos] );
+ }
+ TYPELIB_DANGER_RELEASE( pReturnType );
+ (*pUnoI->release)( pUnoI );
+
+ throw aExc;
+ }
+ }
+ }
+
+ uno_Any aUnoExc;
+ uno_Any * pUnoExc = &aUnoExc;
+
+ (*pUnoI->pDispatcher)(
+ pUnoI, getTypeDescr(), pUnoReturn, ppUnoArgs, &pUnoExc );
+ (*pUnoI->release)( pUnoI );
+
+ Any aRet;
+ if (pUnoExc)
+ {
+ // cleanup
+ while (nParams--)
+ {
+ if (pParams[nParams].bIn)
+ uno_destructData( ppUnoArgs[nParams], ppParamTypes[nParams], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nParams] );
+ }
+ TYPELIB_DANGER_RELEASE( pReturnType );
+
+ InvocationTargetException aExc;
+ aExc.Context = *o3tl::doAccess<Reference<XInterface>>(rObj);
+ aExc.Message = "exception occurred during invocation!";
+ uno_any_destruct(
+ &aExc.TargetException,
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_type_copyAndConvertData(
+ &aExc.TargetException, pUnoExc, cppu::UnoType<Any>::get().getTypeLibType(),
+ getReflection()->getUno2Cpp().get() );
+ uno_any_destruct( pUnoExc, nullptr );
+ throw aExc;
+ }
+ else
+ {
+ // reconvert arguments and cleanup
+ while (nParams--)
+ {
+ if (pParams[nParams].bOut) // write back
+ {
+ uno_any_destruct(
+ &pCppArgs[nParams],
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert(
+ &pCppArgs[nParams], ppUnoArgs[nParams], ppParamTypes[nParams],
+ getReflection()->getUno2Cpp().get() );
+ }
+ uno_destructData( ppUnoArgs[nParams], ppParamTypes[nParams], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nParams] );
+ }
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert(
+ &aRet, pUnoReturn, pReturnType,
+ getReflection()->getUno2Cpp().get() );
+ uno_destructData( pUnoReturn, pReturnType, nullptr );
+ TYPELIB_DANGER_RELEASE( pReturnType );
+ }
+ return aRet;
+ }
+ throw IllegalArgumentException(
+ "illegal destination object given!",
+ static_cast<XWeak *>(static_cast<OWeakObject *>(this)), 0 );
+}
+
+
+InterfaceIdlClassImpl::~InterfaceIdlClassImpl()
+{
+ for ( sal_Int32 nPos = _nMethods + _nAttributes; nPos--; )
+ typelib_typedescription_release( _pSortedMemberInit[nPos].second );
+}
+
+
+Sequence< Reference< XIdlClass > > InterfaceIdlClassImpl::getSuperclasses()
+{
+ ::osl::MutexGuard aGuard(getMutexAccess());
+ if (!_xSuperClasses.hasElements()) {
+ typelib_InterfaceTypeDescription * pType = getTypeDescr();
+ _xSuperClasses.realloc(pType->nBaseTypes);
+ auto pSuperClasses = _xSuperClasses.getArray();
+ for (sal_Int32 i = 0; i < pType->nBaseTypes; ++i) {
+ pSuperClasses[i] = getReflection()->forType(
+ &pType->ppBaseTypes[i]->aBase);
+ OSL_ASSERT(_xSuperClasses[i].is());
+ }
+ }
+ return _xSuperClasses;
+}
+
+void InterfaceIdlClassImpl::initMembers()
+{
+ sal_Int32 nAll = getTypeDescr()->nAllMembers;
+ std::unique_ptr<MemberInit[]> pSortedMemberInit(new MemberInit[nAll]);
+ typelib_TypeDescriptionReference ** ppAllMembers = getTypeDescr()->ppAllMembers;
+
+ for ( sal_Int32 nPos = 0; nPos < nAll; ++nPos )
+ {
+ sal_Int32 nIndex;
+ if (ppAllMembers[nPos]->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
+ {
+ // methods to front
+ nIndex = _nMethods;
+ ++_nMethods;
+ }
+ else
+ {
+ ++_nAttributes;
+ nIndex = (nAll - _nAttributes);
+ // attributes at the back
+ }
+
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescriptionreference_getDescription( &pTD, ppAllMembers[nPos] );
+ assert(pTD && "### cannot get type description!");
+ pSortedMemberInit[nIndex].first = reinterpret_cast<typelib_InterfaceMemberTypeDescription *>(pTD)->pMemberName;
+ pSortedMemberInit[nIndex].second = pTD;
+ }
+
+ _pSortedMemberInit = std::move(pSortedMemberInit);
+}
+
+sal_Bool InterfaceIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ if (xType.is() && xType->getTypeClass() == TypeClass_INTERFACE)
+ {
+ if (equals( xType ))
+ return true;
+ else
+ {
+ const Sequence< Reference< XIdlClass > > & rSeq = xType->getSuperclasses();
+ if (std::any_of(rSeq.begin(), rSeq.end(),
+ [this](const Reference<XIdlClass>& rType){ return isAssignableFrom(rType); }))
+ return true;
+ }
+ }
+ return false;
+}
+
+Uik InterfaceIdlClassImpl::getUik()
+{
+ return Uik(0, 0, 0, 0, 0);
+ // Uiks are deprecated and this function must not be called
+}
+
+Sequence< Reference< XIdlMethod > > InterfaceIdlClassImpl::getMethods()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ // create methods sequence
+ Sequence< Reference< XIdlMethod > > aRet( _nMethods );
+ Reference< XIdlMethod > * pRet = aRet.getArray();
+ for ( sal_Int32 nPos = _nMethods; nPos--; )
+ {
+
+ /*_aName2Method[_pSortedMemberInit[nPos].first] = */pRet[nPos] = new IdlInterfaceMethodImpl(
+ getReflection(), _pSortedMemberInit[nPos].first,
+ _pSortedMemberInit[nPos].second, IdlClassImpl::getTypeDescr() );
+ }
+ return aRet;
+}
+
+Sequence< Reference< XIdlField > > InterfaceIdlClassImpl::getFields()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ // create fields sequence
+ Sequence< Reference< XIdlField > > aRet( _nAttributes );
+ Reference< XIdlField > * pRet = aRet.getArray();
+ for ( sal_Int32 nPos = _nAttributes; nPos--; )
+ {
+ /*_aName2Field[_pSortedMemberInit[_nMethods+nPos].first] = */pRet[_nAttributes-nPos-1] =
+ new IdlAttributeFieldImpl(
+ getReflection(), _pSortedMemberInit[_nMethods+nPos].first,
+ _pSortedMemberInit[_nMethods+nPos].second, IdlClassImpl::getTypeDescr() );
+ }
+ return aRet;
+}
+
+Reference< XIdlMethod > InterfaceIdlClassImpl::getMethod( const OUString & rName )
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ Reference< XIdlMethod > xRet;
+
+ // try weak map
+ const OUString2Method::const_iterator iFind( _aName2Method.find( rName ) );
+ if (iFind != _aName2Method.end())
+ xRet = (*iFind).second; // harden ref
+
+ if (! xRet.is())
+ {
+ for ( sal_Int32 nPos = _nMethods; nPos--; )
+ {
+ if (_pSortedMemberInit[nPos].first == rName)
+ {
+ _aName2Method[rName] = xRet = new IdlInterfaceMethodImpl(
+ getReflection(), rName,
+ _pSortedMemberInit[nPos].second, IdlClassImpl::getTypeDescr() );
+ break;
+ }
+ }
+ }
+ return xRet;
+}
+
+Reference< XIdlField > InterfaceIdlClassImpl::getField( const OUString & rName )
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ Reference< XIdlField > xRet;
+
+ // try weak map
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ xRet = (*iFind).second; // harden ref
+
+ if (! xRet.is())
+ {
+ for ( sal_Int32 nPos = _nAttributes; nPos--; )
+ {
+ if (_pSortedMemberInit[_nMethods+nPos].first == rName)
+ {
+ _aName2Field[rName] = xRet = new IdlAttributeFieldImpl(
+ getReflection(), rName,
+ _pSortedMemberInit[_nMethods+nPos].second, IdlClassImpl::getTypeDescr() );
+ break;
+ }
+ }
+ }
+ return xRet;
+}
+
+void InterfaceIdlClassImpl::createObject( Any & rObj )
+{
+ // interfaces cannot be constructed
+ rObj.clear();
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/lrucache.hxx b/stoc/source/corereflection/lrucache.hxx
new file mode 100644
index 000000000..d5eebe804
--- /dev/null
+++ b/stoc/source/corereflection/lrucache.hxx
@@ -0,0 +1,209 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX
+#define INCLUDED_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX
+
+// __CACHE_DIAGNOSE forces cache size to 4 and works only for OUString keys
+// #define __CACHE_DIAGNOSE 1
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+
+namespace com::sun::star::uno { class Any; }
+
+/** Implementation of a least recently used (lru) cache.
+ <br>
+*/
+template< class t_Key, class t_Val, class t_KeyHash >
+class LRU_Cache
+{
+ struct CacheEntry
+ {
+ t_Key aKey;
+ t_Val aVal;
+ CacheEntry * pPred;
+ CacheEntry * pSucc;
+ };
+ typedef std::unordered_map< t_Key, CacheEntry *, t_KeyHash > t_Key2Element;
+
+ mutable std::mutex _aCacheMutex;
+ sal_Int32 _nCachedElements;
+ t_Key2Element _aKey2Element;
+
+ std::unique_ptr<CacheEntry[]> _pBlock;
+ mutable CacheEntry * _pHead;
+ mutable CacheEntry * _pTail;
+ inline void toFront( CacheEntry * pEntry ) const;
+
+public:
+ /** Constructor:
+ <br>
+ @param nCachedElements number of elements to be cached; default param set to 128
+ */
+ explicit inline LRU_Cache();
+
+ /** Retrieves a value from the cache. Returns default constructed value,
+ if none was found.
+ <br>
+ @param rKey a key
+ @return value
+ */
+ inline t_Val getValue( const t_Key & rKey ) const;
+ /** Sets a value to be cached for given key.
+ <br>
+ @param rKey a key
+ @param rValue a value
+ */
+ inline void setValue( const t_Key & rKey, const t_Val & rValue );
+ /** Clears the cache, thus releasing all cached elements and keys.
+ <br>
+ */
+ inline void clear();
+};
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline LRU_Cache< t_Key, t_Val, t_KeyHash >::LRU_Cache()
+#ifdef __CACHE_DIAGNOSE
+ : _nCachedElements( 4 )
+#else
+ : _nCachedElements( 256 )
+#endif
+ , _pBlock( nullptr )
+ , _pHead( nullptr )
+ , _pTail( nullptr )
+{
+ _pBlock.reset(new CacheEntry[_nCachedElements]);
+ _pHead = _pBlock.get();
+ _pTail = _pBlock.get() + _nCachedElements - 1;
+ for (sal_Int32 nPos = _nCachedElements; nPos--;)
+ {
+ _pBlock[nPos].pPred = _pBlock.get() + nPos - 1;
+ _pBlock[nPos].pSucc = _pBlock.get() + nPos + 1;
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::toFront( CacheEntry * pEntry ) const
+{
+ if (pEntry != _pHead)
+ {
+ // cut out element
+ if (pEntry == _pTail)
+ {
+ _pTail = pEntry->pPred;
+ }
+ else
+ {
+ pEntry->pSucc->pPred = pEntry->pPred;
+ pEntry->pPred->pSucc = pEntry->pSucc;
+ }
+ // push to front
+ _pHead->pPred = pEntry;
+ pEntry->pSucc = _pHead;
+ _pHead = pEntry;
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline t_Val LRU_Cache< t_Key, t_Val, t_KeyHash >::getValue( const t_Key & rKey ) const
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) );
+ if (iFind != _aKey2Element.end())
+ {
+ CacheEntry * pEntry = (*iFind).second;
+ toFront( pEntry );
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> retrieved element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" from cache <" );
+#endif
+ return pEntry->aVal;
+ }
+ return t_Val();
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::setValue(
+ const t_Key & rKey, const t_Val & rValue )
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ if (_nCachedElements > 0)
+ {
+ const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) );
+
+ CacheEntry * pEntry;
+ if (iFind == _aKey2Element.end())
+ {
+ pEntry = _pTail; // erase last element
+#ifdef __CACHE_DIAGNOSE
+ if (pEntry->aKey.getLength())
+ {
+ SAL_INFO("stoc.corerefl", "> kicking element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" from cache <" );
+ }
+#endif
+ _aKey2Element.erase( pEntry->aKey );
+ pEntry->aKey = rKey;
+ _aKey2Element[ rKey ] = pEntry;
+ }
+ else
+ {
+ pEntry = (*iFind).second;
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> replacing element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" in cache <" );
+#endif
+ }
+ pEntry->aVal = rValue;
+ toFront( pEntry );
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::clear()
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ _aKey2Element.clear();
+ for ( sal_Int32 nPos = _nCachedElements; nPos--; )
+ {
+ _pBlock[nPos].aKey = t_Key();
+ _pBlock[nPos].aVal = t_Val();
+ }
+ _nCachedElements = 0;
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> cleared cache <" );
+#endif
+}
+
+
+/** Template instance for OUString keys, Any values.<br>
+*/
+typedef LRU_Cache< OUString, css::uno::Any, OUStringHash >
+ LRU_CacheAnyByOUString;
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/reflection.component b/stoc/source/corereflection/reflection.component
new file mode 100644
index 000000000..70ccb68e0
--- /dev/null
+++ b/stoc/source/corereflection/reflection.component
@@ -0,0 +1,28 @@
+<?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.CoreReflection"
+ constructor="com_sun_star_comp_stoc_CoreReflection_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.reflection.CoreReflection"/>
+ <singleton name="com.sun.star.reflection.theCoreReflection"/>
+ </implementation>
+</component>
diff --git a/stoc/source/defaultregistry/defaultregistry.cxx b/stoc/source/defaultregistry/defaultregistry.cxx
new file mode 100644
index 000000000..866648439
--- /dev/null
+++ b/stoc/source/defaultregistry/defaultregistry.cxx
@@ -0,0 +1,1193 @@
+/* -*- 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/mutex.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase4.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace css::uno;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::container;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+class NestedRegistryImpl : public WeakAggImplHelper4 < XSimpleRegistry, XInitialization, XServiceInfo, XEnumerationAccess >
+{
+public:
+ NestedRegistryImpl( );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XSimpleRegistry
+ virtual OUString SAL_CALL getURL() override;
+ virtual void SAL_CALL open( const OUString& rURL, sal_Bool bReadOnly, sal_Bool bCreate ) override;
+ virtual sal_Bool SAL_CALL isValid( ) override;
+ virtual void SAL_CALL close( ) override;
+ virtual void SAL_CALL destroy( ) override;
+ virtual Reference< XRegistryKey > SAL_CALL getRootKey( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL mergeKey( const OUString& aKeyName, const OUString& aUrl ) override;
+
+ // XEnumerationAccess
+ virtual Reference< XEnumeration > SAL_CALL createEnumeration( ) override;
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ friend class NestedKeyImpl;
+protected:
+ Mutex m_mutex;
+ sal_uInt32 m_state;
+ Reference<XSimpleRegistry> m_localReg;
+ Reference<XSimpleRegistry> m_defaultReg;
+
+};
+
+
+// class NestedKeyImpl the implementation of interface XRegistryKey
+
+class NestedKeyImpl : public WeakImplHelper< XRegistryKey >
+{
+public:
+ NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
+ Reference<XRegistryKey>& localKey,
+ Reference<XRegistryKey>& defaultKey);
+
+ NestedKeyImpl( const OUString& aKeyName,
+ NestedKeyImpl* pKey);
+
+ // XRegistryKey
+ virtual OUString SAL_CALL getKeyName() override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL isValid( ) override;
+ virtual RegistryKeyType SAL_CALL getKeyType( const OUString& rKeyName ) override;
+ virtual RegistryValueType SAL_CALL getValueType( ) override;
+ virtual sal_Int32 SAL_CALL getLongValue( ) override;
+ virtual void SAL_CALL setLongValue( sal_Int32 value ) override;
+ virtual Sequence< sal_Int32 > SAL_CALL getLongListValue( ) override;
+ virtual void SAL_CALL setLongListValue( const css::uno::Sequence< sal_Int32 >& seqValue ) override;
+ virtual OUString SAL_CALL getAsciiValue( ) override;
+ virtual void SAL_CALL setAsciiValue( const OUString& value ) override;
+ virtual Sequence< OUString > SAL_CALL getAsciiListValue( ) override;
+ virtual void SAL_CALL setAsciiListValue( const css::uno::Sequence< OUString >& seqValue ) override;
+ virtual OUString SAL_CALL getStringValue( ) override;
+ virtual void SAL_CALL setStringValue( const OUString& value ) override;
+ virtual Sequence< OUString > SAL_CALL getStringListValue( ) override;
+ virtual void SAL_CALL setStringListValue( const css::uno::Sequence< OUString >& seqValue ) override;
+ virtual Sequence< sal_Int8 > SAL_CALL getBinaryValue( ) override;
+ virtual void SAL_CALL setBinaryValue( const css::uno::Sequence< sal_Int8 >& value ) override;
+ virtual Reference< XRegistryKey > SAL_CALL openKey( const OUString& aKeyName ) override;
+ virtual Reference< XRegistryKey > SAL_CALL createKey( const OUString& aKeyName ) override;
+ virtual void SAL_CALL closeKey( ) override;
+ virtual void SAL_CALL deleteKey( const OUString& rKeyName ) override;
+ virtual Sequence< Reference< XRegistryKey > > SAL_CALL openKeys( ) override;
+ virtual Sequence< OUString > SAL_CALL getKeyNames( ) override;
+ virtual sal_Bool SAL_CALL createLink( const OUString& aLinkName, const OUString& aLinkTarget ) override;
+ virtual void SAL_CALL deleteLink( const OUString& rLinkName ) override;
+ virtual OUString SAL_CALL getLinkTarget( const OUString& rLinkName ) override;
+ virtual OUString SAL_CALL getResolvedName( const OUString& aKeyName ) override;
+
+protected:
+ void computeChanges();
+ OUString computeName(const OUString& name);
+
+ OUString m_name;
+ sal_uInt32 m_state;
+ rtl::Reference<NestedRegistryImpl> m_xRegistry;
+ Reference<XRegistryKey> m_localKey;
+ Reference<XRegistryKey> m_defaultKey;
+};
+
+
+NestedKeyImpl::NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
+ Reference<XRegistryKey>& localKey,
+ Reference<XRegistryKey>& defaultKey )
+ : m_state(pDefaultRegistry->m_state), m_xRegistry(pDefaultRegistry), m_localKey(localKey), m_defaultKey(defaultKey)
+{
+ if (m_localKey.is())
+ {
+ m_name = m_localKey->getKeyName();
+ }
+ else if (m_defaultKey.is())
+ {
+ m_name = m_defaultKey->getKeyName();
+ }
+}
+
+
+NestedKeyImpl::NestedKeyImpl( const OUString& rKeyName,
+ NestedKeyImpl* pKey)
+ : m_xRegistry(pKey->m_xRegistry)
+{
+ if (pKey->m_localKey.is() && pKey->m_localKey->isValid())
+ {
+ m_localKey = pKey->m_localKey->openKey(rKeyName);
+ }
+ if (pKey->m_defaultKey.is() && pKey->m_defaultKey->isValid())
+ {
+ m_defaultKey = pKey->m_defaultKey->openKey(rKeyName);
+ }
+
+ if (m_localKey.is())
+ {
+ m_name = m_localKey->getKeyName();
+ }
+ else if (m_defaultKey.is())
+ {
+ m_name = m_defaultKey->getKeyName();
+ }
+
+ m_state = m_xRegistry->m_state;
+}
+
+void NestedKeyImpl::computeChanges()
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( m_state == m_xRegistry->m_state )
+ return;
+
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+
+ Reference<XRegistryKey> tmpKey = rootKey->openKey(m_name);
+
+ if ( tmpKey.is() )
+ {
+ m_localKey = rootKey->openKey(m_name);
+ }
+
+ m_state = m_xRegistry->m_state;
+}
+
+
+// NestedKey_Impl::computeName()
+
+OUString NestedKeyImpl::computeName(const OUString& name)
+{
+ OUString resLocalName, resDefaultName;
+
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ try
+ {
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ resLocalName = m_localKey->getResolvedName(name);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getResolvedName(name);
+ }
+
+ if ( !resLocalName.isEmpty() && m_xRegistry->m_defaultReg->isValid() )
+ {
+ Reference<XRegistryKey> localRoot(m_xRegistry->m_localReg->getRootKey());
+ Reference<XRegistryKey> defaultRoot(m_xRegistry->m_defaultReg->getRootKey());
+
+ resDefaultName = defaultRoot->getResolvedName(resLocalName);
+
+ sal_uInt32 count = 100;
+
+ while (resLocalName != resDefaultName && count > 0)
+ {
+ count--;
+
+ if (resLocalName.isEmpty() || resDefaultName.isEmpty())
+ throw InvalidRegistryException();
+
+ resLocalName = localRoot->getResolvedName(resDefaultName);
+ resDefaultName = defaultRoot->getResolvedName(resLocalName);
+ }
+ }
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return resLocalName;
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getKeyName()
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ return m_name;
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::isReadOnly( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( !m_localKey.is() || !m_localKey->isValid() )
+ throw InvalidRegistryException();
+
+ return m_localKey->isReadOnly();
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::isValid( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ return ((m_localKey.is() && m_localKey->isValid()) ||
+ (m_defaultKey.is() && m_defaultKey->isValid()) );
+}
+
+
+RegistryKeyType SAL_CALL NestedKeyImpl::getKeyType( const OUString& rKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getKeyType(rKeyName);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getKeyType(rKeyName);
+ }
+
+ return RegistryKeyType_KEY;
+}
+
+
+RegistryValueType SAL_CALL NestedKeyImpl::getValueType( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getValueType();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getValueType();
+ }
+
+ return RegistryValueType_NOT_DEFINED;
+}
+
+
+sal_Int32 SAL_CALL NestedKeyImpl::getLongValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getLongValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getLongValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setLongValue( sal_Int32 value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setLongValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setLongValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< sal_Int32 > SAL_CALL NestedKeyImpl::getLongListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getLongListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getLongListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setLongListValue( const Sequence< sal_Int32 >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setLongListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setLongListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getAsciiValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getAsciiValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getAsciiValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setAsciiValue( const OUString& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setAsciiValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setAsciiValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getAsciiListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getAsciiListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getAsciiListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setAsciiListValue( const Sequence< OUString >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setAsciiListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setAsciiListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getStringValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getStringValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getStringValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setStringValue( const OUString& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setStringValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setStringValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getStringListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getStringListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getStringListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setStringListValue( const Sequence< OUString >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setStringListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setStringListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< sal_Int8 > SAL_CALL NestedKeyImpl::getBinaryValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getBinaryValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getBinaryValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setBinaryValue( const Sequence< sal_Int8 >& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setBinaryValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setBinaryValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedKeyImpl::openKey( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ throw InvalidRegistryException();
+
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localKey = m_xRegistry->m_localReg->getRootKey()->openKey(resolvedName);
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+ }
+
+ if ( localKey.is() || defaultKey.is() )
+ {
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ else
+ {
+ return Reference<XRegistryKey>();
+ }
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedKeyImpl::createKey( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( (!m_localKey.is() && !m_defaultKey.is()) ||
+ (m_localKey.is() && m_localKey->isReadOnly()) )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ throw InvalidRegistryException();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);
+ if ( localKey.is() )
+ {
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+ }
+
+ m_state = m_xRegistry->m_state++;
+
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ }
+ else
+ {
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+
+ localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);
+
+ if ( localKey.is() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+
+ m_state = m_xRegistry->m_state++;
+
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ }
+ }
+
+ return Reference<XRegistryKey>();
+}
+
+
+void SAL_CALL NestedKeyImpl::closeKey( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->closeKey();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ m_defaultKey->closeKey();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::deleteKey( const OUString& rKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() || !m_localKey->isValid() ||
+ m_localKey->isReadOnly() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(rKeyName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ m_xRegistry->m_localReg->getRootKey()->deleteKey(resolvedName);
+}
+
+
+Sequence< Reference< XRegistryKey > > SAL_CALL NestedKeyImpl::openKeys( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Sequence<OUString> localSeq, defaultSeq;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localSeq = m_localKey->getKeyNames();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultSeq = m_defaultKey->getKeyNames();
+ }
+
+ std::vector< Reference<XRegistryKey> > retVec;
+ retVec.reserve(localSeq.getLength() + defaultSeq.getLength());
+
+ auto lKeyNameToRegKey = [this](const OUString& rName) -> Reference<XRegistryKey> {
+ sal_Int32 lastIndex = rName.lastIndexOf('/');
+ OUString name = rName.copy(lastIndex);
+ return new NestedKeyImpl(name, this);
+ };
+
+ for (const auto& rKeyName : std::as_const(localSeq))
+ retVec.push_back(lKeyNameToRegKey(rKeyName));
+
+ for (const auto& rKeyName : std::as_const(defaultSeq))
+ {
+ if ( comphelper::findValue(localSeq, rKeyName) == -1 )
+ {
+ retVec.push_back(lKeyNameToRegKey(rKeyName));
+ }
+ }
+
+ return comphelper::containerToSequence(retVec);
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getKeyNames( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Sequence<OUString> localSeq, defaultSeq;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localSeq = m_localKey->getKeyNames();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultSeq = m_defaultKey->getKeyNames();
+ }
+
+ return comphelper::combineSequences(localSeq, defaultSeq);
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::createLink( const OUString& aLinkName, const OUString& aLinkTarget )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+
+ bool isCreated = false;
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = aLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = aLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += aLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + aLinkName;
+ else
+ resolvedName = m_name + "/" + aLinkName;
+ }
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
+ }
+ else
+ {
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+
+ isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
+ }
+ }
+
+ if ( isCreated )
+ m_state = m_xRegistry->m_state++;
+
+ return isCreated;
+}
+
+
+void SAL_CALL NestedKeyImpl::deleteLink( const OUString& rLinkName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = rLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = rLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += rLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + rLinkName;
+ else
+ resolvedName = m_name + "/" + rLinkName;
+ }
+
+ if ( !m_localKey.is() || !m_localKey->isValid() ||
+ m_localKey->isReadOnly() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ m_xRegistry->m_localReg->getRootKey()->deleteLink(resolvedName);
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getLinkTarget( const OUString& rLinkName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = rLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = rLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += rLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + rLinkName;
+ else
+ resolvedName = m_name + "/" + rLinkName;
+ }
+
+ OUString linkTarget;
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ try
+ {
+ linkTarget = m_xRegistry->m_localReg->getRootKey()->getLinkTarget(resolvedName);
+ return linkTarget;
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+ }
+
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ linkTarget = m_xRegistry->m_defaultReg->getRootKey()->getLinkTarget(resolvedName);
+
+ return linkTarget;
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getResolvedName( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ return resolvedName;
+}
+
+
+// DefaultRegistry Implementation
+
+
+NestedRegistryImpl::NestedRegistryImpl( )
+ : m_state(0)
+{}
+
+class RegistryEnumueration : public WeakImplHelper< XEnumeration >
+{
+public:
+ RegistryEnumueration(
+ const Reference< XSimpleRegistry > &r1,
+ const Reference< XSimpleRegistry > &r2 )
+ : m_xReg1( r1 ) , m_xReg2( r2 )
+ {}
+public:
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual Any SAL_CALL nextElement( ) override;
+
+private:
+ Reference< XSimpleRegistry > m_xReg1;
+ Reference< XSimpleRegistry > m_xReg2;
+};
+
+sal_Bool RegistryEnumueration::hasMoreElements( )
+{
+ return m_xReg1.is() || m_xReg2.is();
+}
+
+Any RegistryEnumueration::nextElement( )
+{
+ Any a;
+ if( m_xReg1.is() )
+ {
+ a <<= m_xReg1;
+ m_xReg1.clear();
+ }
+ else if( m_xReg2.is() )
+ {
+ a <<= m_xReg2;
+ m_xReg2.clear();
+ }
+ else
+ {
+ throw NoSuchElementException( "NestedRegistry: no nextElement() !" );
+ }
+ return a;
+}
+
+
+Reference< XEnumeration > NestedRegistryImpl::createEnumeration( )
+{
+ MutexGuard guard( m_mutex );
+ return new RegistryEnumueration( m_localReg, m_defaultReg );
+}
+
+Type NestedRegistryImpl::getElementType( )
+{
+ return cppu::UnoType<decltype(m_localReg)>::get();
+}
+
+sal_Bool SAL_CALL NestedRegistryImpl::hasElements( )
+{
+ MutexGuard guard( m_mutex );
+ return m_localReg.is() || m_defaultReg.is();
+}
+
+
+OUString SAL_CALL NestedRegistryImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.stoc.NestedRegistry";
+}
+
+sal_Bool SAL_CALL NestedRegistryImpl::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL NestedRegistryImpl::getSupportedServiceNames( )
+{
+ Sequence< OUString > seqNames { "com.sun.star.registry.NestedRegistry" };
+ return seqNames;
+}
+
+
+void SAL_CALL NestedRegistryImpl::initialize( const Sequence< Any >& aArguments )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( (aArguments.getLength() == 2) &&
+ (aArguments[0].getValueType().getTypeClass() == TypeClass_INTERFACE) &&
+ (aArguments[1].getValueType().getTypeClass() == TypeClass_INTERFACE) )
+ {
+ aArguments[0] >>= m_localReg;
+ aArguments[1] >>= m_defaultReg;
+ if ( m_localReg == m_defaultReg )
+ m_defaultReg.clear();
+ }
+}
+
+
+OUString SAL_CALL NestedRegistryImpl::getURL()
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( m_localReg.is() && m_localReg->isValid() )
+ return m_localReg->getURL();
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return OUString();
+}
+
+
+void SAL_CALL NestedRegistryImpl::open( const OUString&, sal_Bool, sal_Bool )
+{
+ throw InvalidRegistryException(
+ "the 'open' method is not specified for a nested registry" );
+}
+
+
+sal_Bool SAL_CALL NestedRegistryImpl::isValid( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( (m_localReg.is() && m_localReg->isValid()) ||
+ (m_defaultReg.is() && m_defaultReg->isValid()) )
+ return true;
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return false;
+}
+
+
+void SAL_CALL NestedRegistryImpl::close( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( m_localReg.is() && m_localReg->isValid() )
+ {
+ m_localReg->close();
+ }
+ if ( m_defaultReg.is() && m_defaultReg->isValid() )
+ {
+ m_defaultReg->close();
+ }
+}
+
+
+void SAL_CALL NestedRegistryImpl::destroy( )
+{
+ throw InvalidRegistryException(
+ "the 'destroy' method is not specified for a nested registry" );
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedRegistryImpl::getRootKey( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( !m_localReg.is() || !m_localReg->isValid() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ localKey = m_localReg->getRootKey();
+
+ if ( localKey.is() )
+ {
+ if ( m_defaultReg.is() && m_defaultReg->isValid() )
+ {
+ defaultKey = m_defaultReg->getRootKey();
+ }
+
+ return new NestedKeyImpl(this, localKey, defaultKey);
+ }
+
+ return Reference<XRegistryKey>();
+}
+
+
+sal_Bool SAL_CALL NestedRegistryImpl::isReadOnly( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( m_localReg.is() && m_localReg->isValid() )
+ return m_localReg->isReadOnly();
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return false;
+}
+
+
+void SAL_CALL NestedRegistryImpl::mergeKey( const OUString& aKeyName, const OUString& aUrl )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( m_localReg.is() && m_localReg->isValid() )
+ {
+ m_localReg->mergeKey(aKeyName, aUrl);
+
+ m_state++;
+ }
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_NestedRegistry_get_implementation(
+ SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new NestedRegistryImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/implreg.cxx b/stoc/source/implementationregistration/implreg.cxx
new file mode 100644
index 000000000..7d697e41f
--- /dev/null
+++ b/stoc/source/implementationregistration/implreg.cxx
@@ -0,0 +1,1580 @@
+/* -*- 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 <string.h>
+#include <string_view>
+#include <vector>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/registry/XImplementationRegistration2.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/reflection/XServiceTypeDescription.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "mergekeys.hxx"
+
+#if defined(_WIN32)
+#include <io.h>
+#endif
+
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::loader;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::registry;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+constexpr OUStringLiteral slash_UNO_slash_REGISTRY_LINKS
+ = u"/UNO/REGISTRY_LINKS";
+constexpr OUStringLiteral slash_IMPLEMENTATIONS
+ = u"/IMPLEMENTATIONS";
+constexpr OUStringLiteral slash_UNO
+ = u"/UNO";
+constexpr OUStringLiteral slash_UNO_slash_SERVICES
+ = u"/UNO/SERVICES";
+constexpr OUStringLiteral slash_UNO_slash_SINGLETONS
+ = u"/UNO/SINGLETONS";
+constexpr OUStringLiteral slash_SERVICES
+ = u"/SERVICES/";
+constexpr OUStringLiteral slash_UNO_slash_LOCATION
+ = u"/UNO/LOCATION";
+constexpr OUStringLiteral slash_UNO_slash_ACTIVATOR
+ = u"/UNO/ACTIVATOR";
+constexpr OUStringLiteral colon_old
+ = u":old";
+constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry
+ = u"com.sun.star.registry.SimpleRegistry";
+constexpr OUStringLiteral Registry
+ = u"Registry";
+
+// static deleteAllLinkReferences()
+
+void deleteAllLinkReferences(const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Reference < XRegistryKey > xKey = xSource->openKey(
+ slash_UNO_slash_REGISTRY_LINKS );
+
+ if (!(xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST)))
+ return;
+
+ const Sequence<OUString> linkNames = xKey->getAsciiListValue();
+
+ if (!linkNames.hasElements())
+ return;
+
+ OUString aLinkName;
+ OUString aLinkParent;
+ Reference < XRegistryKey > xLinkParent;
+ const sal_Unicode* pTmpName = nullptr;
+ const sal_Unicode* pShortName = nullptr;
+ sal_Int32 sEnd = 0;
+
+ for (const OUString& rLinkName : linkNames)
+ {
+ aLinkName = rLinkName;
+
+ pTmpName = aLinkName.getStr();
+
+ if (pTmpName[0] != L'/')
+ continue;
+
+ sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName = pTmpName+nIndex;
+
+ while (pShortName && pShortName[1] == L'%')
+ {
+ nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName += nIndex+2;
+ }
+
+ if (pShortName)
+ {
+ aLinkName = aLinkName.copy(0, pShortName - pTmpName);
+ }
+
+ xReg->getRootKey()->deleteLink(aLinkName);
+
+ sEnd = aLinkName.lastIndexOf( '/' );
+
+ aLinkParent = aLinkName.copy(0, sEnd);
+
+ while(!aLinkParent.isEmpty())
+ {
+ xLinkParent = xReg->getRootKey()->openKey(aLinkParent);
+
+ if (xLinkParent.is() && !xLinkParent->getKeyNames().hasElements())
+ {
+ aLinkName = aLinkParent;
+
+ xReg->getRootKey()->deleteKey(aLinkParent);
+
+ sEnd = aLinkName.lastIndexOf( '/' );
+
+ aLinkParent = aLinkName.copy(0, sEnd);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+// static prepareLink
+
+void prepareLink( const Reference < XSimpleRegistry > & xDest,
+ const Reference < XRegistryKey > & xSource,
+ const OUString& link)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ OUString linkRefName = xSource->getKeyName();
+ OUString linkName(link);
+ bool isRelativ = false;
+
+ const sal_Unicode* pTmpName = link.getStr();
+ const sal_Unicode* pShortName;
+ sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName = pTmpName+nIndex;
+
+ if (pTmpName[0] != L'/')
+ isRelativ = true;
+
+ while (pShortName && pShortName[1] == L'%')
+ {
+ nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName += nIndex+2;
+ }
+
+ if (pShortName)
+ {
+ linkRefName += link.subView(pShortName - pTmpName + 1);
+ linkName = link.copy(0, pShortName - pTmpName);
+ }
+
+ if (isRelativ)
+ xSource->createLink(linkName, linkRefName);
+ else
+ xDest->getRootKey()->createLink(linkName, linkRefName);
+}
+
+
+// static searchImplForLink
+
+OUString searchImplForLink(
+ const Reference < XRegistryKey > & xRootKey,
+ std::u16string_view linkName,
+ std::u16string_view implName )
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys( xKey->openKeys() );
+ OUString key_name( slash_UNO + linkName );
+
+ for (const Reference < XRegistryKey >& xImplKey : subKeys)
+ {
+ try
+ {
+ if (xImplKey->getKeyType( key_name ) == RegistryKeyType_LINK)
+ {
+ OUString oldImplName = xImplKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
+ if (implName != oldImplName)
+ {
+ return oldImplName;
+ }
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+ }
+ }
+
+ return OUString();
+}
+
+
+// static searchLinkTargetForImpl
+
+OUString searchLinkTargetForImpl(const Reference < XRegistryKey >& xRootKey,
+ std::u16string_view linkName,
+ const OUString& implName)
+{
+ Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
+
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys = xKey->openKeys();
+
+ OUString qualifiedLinkName( slash_UNO + linkName );
+
+ auto pSubKey = std::find_if(subKeys.begin(), subKeys.end(),
+ [&implName, &qualifiedLinkName](const Reference<XRegistryKey>& rSubKey) {
+ OUString tmpImplName = rSubKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
+ return tmpImplName == implName
+ && rSubKey->getKeyType( qualifiedLinkName ) == RegistryKeyType_LINK;
+ });
+ if (pSubKey != subKeys.end())
+ return (*pSubKey)->getLinkTarget( qualifiedLinkName );
+ }
+
+ return OUString();
+}
+
+
+// static createUniqueSubEntry
+
+void createUniqueSubEntry(const Reference < XRegistryKey > & xSuperKey,
+ const OUString& value)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if (!xSuperKey.is())
+ return;
+
+ if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+
+ bool bReady = comphelper::findValue(implEntries, value) != -1;
+
+ if (bReady)
+ {
+ Sequence<OUString> implEntriesNew(length);
+ auto it = implEntriesNew.getArray();
+ *it = value;
+
+ std::copy_if(implEntries.begin(), implEntries.end(), std::next(it),
+ [&value](const OUString& rEntry) { return rEntry != value; });
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ } else
+ {
+ Sequence<OUString> implEntriesNew(length+1);
+ auto it = implEntriesNew.getArray();
+ *it = value;
+
+ std::copy(implEntries.begin(), implEntries.end(), std::next(it));
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+ } else
+ {
+ Sequence<OUString> implEntriesNew { value };
+
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+}
+
+
+// static deleteSubEntry
+
+bool deleteSubEntry(const Reference < XRegistryKey >& xSuperKey, const OUString& value)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), value));
+ bool hasNoImplementations = false;
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ Sequence<OUString> implEntriesNew(length - equals);
+
+ std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
+ [&value](const OUString& rEntry) { return rEntry != value; });
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+
+ if (hasNoImplementations)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// static prepareUserLink
+
+void prepareUserLink(const Reference < XSimpleRegistry >& xDest,
+ const OUString& linkName,
+ const OUString& linkTarget,
+ std::u16string_view implName)
+{
+ Reference < XRegistryKey > xRootKey = xDest->getRootKey();
+
+ if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
+ {
+ OUString oldImplName(searchImplForLink(xRootKey, linkName, implName));
+
+ if (!oldImplName.isEmpty())
+ {
+ createUniqueSubEntry(xDest->getRootKey()->createKey(
+ linkName + colon_old ), oldImplName);
+ }
+ }
+
+ if (xRootKey->isValid())
+ xRootKey->createLink(linkName, linkTarget);
+}
+
+
+// static deleteUserLink
+
+void deletePathIfPossible(const Reference < XRegistryKey >& xRootKey,
+ const OUString& path)
+{
+ try
+ {
+ Sequence<OUString> keyNames(xRootKey->openKey(path)->getKeyNames());
+
+ if (!keyNames.hasElements() &&
+ xRootKey->openKey(path)->getValueType() == RegistryValueType_NOT_DEFINED)
+ {
+ xRootKey->deleteKey(path);
+
+ OUString newPath = path.copy(0, path.lastIndexOf('/'));
+
+ if (newPath.getLength() > 1)
+ deletePathIfPossible(xRootKey, newPath);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+}
+
+
+// static deleteUserLink
+
+void deleteUserLink(const Reference < XRegistryKey >& xRootKey,
+ const OUString& linkName,
+ std::u16string_view linkTarget,
+ const OUString& implName)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ bool bClean = false;
+
+ if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
+ {
+ OUString tmpTarget = xRootKey->getLinkTarget(linkName);
+
+ if (tmpTarget == linkTarget)
+ {
+ xRootKey->deleteLink(linkName);
+ }
+ }
+
+ Reference < XRegistryKey > xOldKey = xRootKey->openKey(
+ linkName + colon_old );
+ if (xOldKey.is())
+ {
+ if (xOldKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xOldKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
+ bool hasNoImplementations = false;
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ OUString oldImpl;
+
+ if (length > equals + 1)
+ {
+ Sequence<OUString> implEntriesNew(length - equals - 1);
+ auto pNewArray = implEntriesNew.getArray();
+
+ sal_Int32 j = 0;
+ bool first = true;
+ for (sal_Int32 i = 0; i < length; i++)
+ {
+ if (implEntries[i] != implName)
+ {
+ if (first)
+ {
+ oldImpl = implEntries[i];
+ first = false;
+ } else
+ {
+ pNewArray[j++] = implEntries[i];
+ }
+ }
+ }
+
+ xOldKey->setAsciiListValue(implEntriesNew);
+ } else
+ {
+ oldImpl = implEntries[0];
+ OUString path(xOldKey->getKeyName());
+ xOldKey->closeKey();
+ xRootKey->deleteKey(path);
+ }
+
+ OUString oldTarget = searchLinkTargetForImpl(xRootKey, linkName, oldImpl);
+ if (!oldTarget.isEmpty())
+ {
+ xRootKey->createLink(linkName, oldTarget);
+ }
+ }
+
+ if (hasNoImplementations)
+ {
+ bClean = true;
+ OUString path(xOldKey->getKeyName());
+ xOldKey->closeKey();
+ xRootKey->deleteKey(path);
+ }
+ }
+ } else
+ {
+ bClean = true;
+ }
+
+ if (bClean)
+ {
+ OUString path = linkName.copy(0, linkName.lastIndexOf('/'));
+ deletePathIfPossible(xRootKey, path);
+ }
+}
+
+
+// static prepareUserKeys
+
+void prepareUserKeys(const Reference < XSimpleRegistry >& xDest,
+ const Reference < XRegistryKey >& xUnoKey,
+ const Reference < XRegistryKey >& xKey,
+ const OUString& implName,
+ bool bRegister)
+{
+ bool hasSubKeys = false;
+
+ Sequence<OUString> keyNames = xKey->getKeyNames();
+
+ OUString relativKey;
+ if (keyNames.hasElements())
+ relativKey = keyNames.getConstArray()[0].copy(xKey->getKeyName().getLength()+1);
+
+ if (keyNames.getLength() == 1 &&
+ xKey->getKeyType(relativKey) == RegistryKeyType_LINK)
+ {
+ hasSubKeys = true;
+
+ OUString linkTarget = xKey->getLinkTarget(relativKey);
+ OUString linkName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
+
+ linkName += "/" + relativKey;
+
+ if (bRegister)
+ {
+ prepareUserLink(xDest, linkName, linkTarget, implName);
+ } else
+ {
+ deleteUserLink(xDest->getRootKey(), linkName, linkTarget, implName);
+ }
+ } else
+ {
+ const Sequence< Reference < XRegistryKey> > subKeys = xKey->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ hasSubKeys = true;
+
+ for (const Reference < XRegistryKey > & rSubKey : subKeys)
+ {
+ prepareUserKeys(xDest, xUnoKey, rSubKey, implName, bRegister);
+ }
+ }
+ }
+
+ if (hasSubKeys)
+ return;
+
+ OUString keyName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
+
+ Reference < XRegistryKey > xRootKey = xDest->getRootKey();
+ if (bRegister)
+ {
+ createUniqueSubEntry(xRootKey->createKey(keyName), implName);
+ }
+ else
+ {
+ Reference< XRegistryKey > rKey = xRootKey->openKey(keyName);
+ if( rKey.is() )
+ {
+ deleteSubEntry(rKey, implName);
+ xRootKey->deleteKey(keyName);
+ }
+
+ OUString path = keyName.copy(0, keyName.lastIndexOf('/'));
+ if( !path.isEmpty() )
+ {
+ deletePathIfPossible(xRootKey, path);
+ }
+ }
+}
+
+
+// static deleteAllImplementations
+
+void deleteAllImplementations( const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource,
+ std::u16string_view locationUrl,
+ std::vector<OUString> & implNames)
+ // throw (InvalidRegistryException, RuntimeException)
+{
+ Sequence < Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ bool hasLocationUrl = false;
+
+ for (const Reference < XRegistryKey> & xImplKey : std::as_const(subKeys))
+ {
+ Reference < XRegistryKey > xKey = xImplKey->openKey(
+ slash_UNO_slash_LOCATION );
+
+ if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCII))
+ {
+ if (xKey->getAsciiValue() == locationUrl)
+ {
+ hasLocationUrl = true;
+
+ OUString implName(xImplKey->getKeyName().copy(1));
+ sal_Int32 firstDot = implName.indexOf('/');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ implNames.push_back(implName);
+
+ deleteAllLinkReferences(xReg, xImplKey);
+
+ xKey = xImplKey->openKey( slash_UNO );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
+
+ for (const Reference < XRegistryKey > & rSubKey2 : subKeys2)
+ {
+ if (rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SERVICES ) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_ACTIVATOR ) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_LOCATION) )
+ {
+ prepareUserKeys(xReg, xKey, rSubKey2, implName, false);
+ }
+ }
+ }
+ }
+ }
+
+ if (hasLocationUrl)
+ {
+ hasLocationUrl = false;
+ OUString path(xImplKey->getKeyName());
+ xImplKey->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ }
+
+ subKeys = xSource->openKeys();
+ if (!subKeys.hasElements())
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ } else
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+}
+
+
+void delete_all_singleton_entries(
+ Reference < registry::XRegistryKey > const & xSingletons_section,
+ ::std::vector< OUString > const & impl_names )
+ // throw (InvalidRegistryException, RuntimeException)
+{
+ Sequence< Reference< registry::XRegistryKey > > singletons( xSingletons_section->openKeys() );
+ Reference< registry::XRegistryKey > const * subkeys = singletons.getConstArray();
+ for ( sal_Int32 nPos = singletons.getLength(); nPos--; )
+ {
+ Reference< registry::XRegistryKey > const & xSingleton = subkeys[ nPos ];
+ Reference< registry::XRegistryKey > xRegisteredImplNames(
+ xSingleton->openKey( "REGISTERED_BY" ) );
+ if (xRegisteredImplNames.is() && xRegisteredImplNames->isValid())
+ {
+ Sequence< OUString > registered_implnames;
+ try
+ {
+ registered_implnames = xRegisteredImplNames->getAsciiListValue();
+ }
+ catch (registry::InvalidValueException &)
+ {
+ }
+ auto aNonConstRange = asNonConstRange(registered_implnames);
+ sal_Int32 nOrigRegLength = registered_implnames.getLength();
+ sal_Int32 nNewLength = nOrigRegLength;
+ for ( sal_Int32 n = nOrigRegLength; n--; )
+ {
+ OUString const & registered_implname = registered_implnames[ n ];
+
+ for (auto const& impl_name : impl_names)
+ {
+ if (impl_name == registered_implname)
+ {
+ aNonConstRange[ n ] = registered_implnames[ nNewLength -1 ];
+ --nNewLength;
+ }
+ }
+ }
+
+ if (nNewLength != nOrigRegLength)
+ {
+ if (0 == nNewLength)
+ {
+ // remove whole entry
+ xRegisteredImplNames->closeKey();
+ xSingleton->deleteKey( "REGISTERED_BY" );
+ // registry key cannot provide its relative name, only absolute :(
+ OUString abs( xSingleton->getKeyName() );
+ xSingletons_section->deleteKey( abs.copy( abs.lastIndexOf( '/' ) +1 ) );
+ }
+ else
+ {
+ registered_implnames.realloc( nNewLength );
+ xRegisteredImplNames->setAsciiListValue( registered_implnames );
+ }
+ }
+ }
+ }
+}
+
+
+// static deleteAllServiceEntries
+
+void deleteAllServiceEntries( const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource,
+ const OUString& implName)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ bool hasNoImplementations = false;
+
+ for (const Reference < XRegistryKey > & xServiceKey : std::as_const(subKeys))
+ {
+ if (xServiceKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xServiceKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ if (equals > 0)
+ {
+ Sequence<OUString> implEntriesNew(length-equals);
+
+ std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
+ [&implName](const OUString& rEntry) { return rEntry != implName; });
+
+ xServiceKey->setAsciiListValue(implEntriesNew);
+ }
+ }
+ }
+
+ if (hasNoImplementations)
+ {
+ hasNoImplementations = false;
+ OUString path(xServiceKey->getKeyName());
+ xServiceKey->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ }
+
+ subKeys = xSource->openKeys();
+ if (!subKeys.hasElements())
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ } else
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+}
+
+
+bool is_supported_service(
+ OUString const & service_name,
+ Reference< reflection::XServiceTypeDescription > const & xService_td )
+{
+ if (xService_td->getName() == service_name)
+ return true;
+ const Sequence< Reference< reflection::XServiceTypeDescription > > seq(
+ xService_td->getMandatoryServices() );
+ return std::any_of(seq.begin(), seq.end(), [&service_name](const auto& rService) {
+ return is_supported_service( service_name, rService ); });
+}
+
+
+void insert_singletons(
+ Reference< registry::XSimpleRegistry > const & xDest,
+ Reference< registry::XRegistryKey > const & xImplKey,
+ Reference< XComponentContext > const & xContext )
+ // throw( registry::InvalidRegistryException, registry::CannotRegisterImplementationException, RuntimeException )
+{
+ // singletons
+ Reference< registry::XRegistryKey > xKey( xImplKey->openKey( "UNO/SINGLETONS" ) );
+ if (!(xKey.is() && xKey->isValid()))
+ return;
+
+ OUString implname( xImplKey->getKeyName().copy( sizeof ("/IMPLEMENTATIONS/") -1 ) );
+ // singleton entries
+ Sequence< Reference< registry::XRegistryKey > > xSingletons_section( xKey->openKeys() );
+ Reference< registry::XRegistryKey > const * p = xSingletons_section.getConstArray();
+ for ( sal_Int32 nPos = xSingletons_section.getLength(); nPos--; )
+ {
+ Reference< registry::XRegistryKey > const & xSingleton = p[ nPos ];
+ OUString singleton_name(
+ xSingleton->getKeyName().copy(
+ implname.getLength() + sizeof ("/IMPLEMENTATIONS//UNO/SINGLETONS/") -1 ) );
+ OUString service_name( xSingleton->getStringValue() );
+
+ OUString keyname( "/SINGLETONS/" + singleton_name );
+ Reference< registry::XRegistryKey > xKey2( xDest->getRootKey()->openKey( keyname ) );
+ if (xKey2.is() && xKey2->isValid())
+ {
+ try
+ {
+ OUString existing_name( xKey2->getStringValue() );
+ if ( existing_name != service_name )
+ {
+ Reference< container::XHierarchicalNameAccess > xTDMgr;
+ OUString the_tdmgr =
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager";
+ xContext->getValueByName( the_tdmgr ) >>= xTDMgr;
+ if (! xTDMgr.is())
+ {
+ throw RuntimeException( "cannot get singleton " + the_tdmgr );
+ }
+ try
+ {
+ Reference< reflection::XServiceTypeDescription > xExistingService_td;
+ xTDMgr->getByHierarchicalName( existing_name ) >>= xExistingService_td;
+ if (! xExistingService_td.is())
+ {
+ throw RuntimeException( "cannot get service type description: " + existing_name );
+ }
+
+ // everything's fine if existing service entry supports the one
+ // to be registered
+ if (! is_supported_service( service_name, xExistingService_td ))
+ {
+ throw registry::CannotRegisterImplementationException(
+ "existing singleton service (" + singleton_name + "=" + existing_name + ") "
+ " does not support given one: " + service_name);
+ }
+ }
+ catch (const container::NoSuchElementException & exc)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "cannot get service type description: " + exc.Message,
+ nullptr, anyEx );
+ }
+ }
+ }
+ catch (registry::InvalidValueException &)
+ {
+ // repair
+ xKey2->setStringValue( service_name );
+ }
+ }
+ else
+ {
+ // insert singleton entry
+ xKey2 = xDest->getRootKey()->createKey( keyname );
+ xKey2->setStringValue( service_name );
+ }
+
+ Reference< registry::XRegistryKey > xRegisteredImplNames(
+ xKey2->openKey( "REGISTERED_BY" ) );
+ if (!xRegisteredImplNames.is() || !xRegisteredImplNames->isValid())
+ {
+ // create
+ xRegisteredImplNames = xKey2->createKey( "REGISTERED_BY" );
+ }
+
+ Sequence< OUString > implnames;
+ try
+ {
+ implnames = xRegisteredImplNames->getAsciiListValue();
+ }
+ catch (registry::InvalidValueException &)
+ {
+ }
+ // check implname is already in
+ if (comphelper::findValue(implnames, implname) == -1)
+ {
+ // append and write back
+ implnames.realloc( implnames.getLength() +1 );
+ implnames.getArray()[ implnames.getLength() -1 ] = implname;
+ xRegisteredImplNames->setAsciiListValue( implnames );
+ }
+ }
+}
+
+
+// static prepareRegistry
+
+void prepareRegistry(
+ const Reference < XSimpleRegistry >& xDest,
+ const Reference < XRegistryKey >& xSource,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ Reference< XComponentContext > const & xContext )
+ // throw ( InvalidRegistryException, CannotRegisterImplementationException, RuntimeException )
+{
+ const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (!subKeys.hasElements())
+ {
+ throw InvalidRegistryException(
+ "prepareRegistry(): source registry is empty" );
+ }
+
+ for (const Reference < XRegistryKey >& xImplKey : subKeys)
+ {
+ Reference < XRegistryKey > xKey = xImplKey->openKey(
+ slash_UNO_slash_SERVICES );
+
+ if (xKey.is())
+ {
+ // update entries in SERVICES section
+ const Sequence< Reference < XRegistryKey > > serviceKeys = xKey->openKeys();
+
+ OUString implName = xImplKey->getKeyName().copy(1);
+ sal_Int32 firstDot = implName.indexOf('/');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ sal_Int32 offset = xKey->getKeyName().getLength() + 1;
+
+ for (const Reference < XRegistryKey >& rServiceKey : serviceKeys)
+ {
+ OUString serviceName = rServiceKey->getKeyName().copy(offset);
+
+ createUniqueSubEntry(
+ xDest->getRootKey()->createKey(
+ slash_SERVICES + serviceName ),
+ implName);
+ }
+
+ xKey = xImplKey->openKey( slash_UNO );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
+
+ for (const Reference < XRegistryKey >& rSubKey2 : subKeys2)
+ {
+ if (rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SERVICES) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
+ rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ))
+ {
+ prepareUserKeys(xDest, xKey, rSubKey2, implName, true);
+ }
+ }
+ }
+ }
+
+ // update LOCATION entry
+ xKey = xImplKey->createKey( slash_UNO_slash_LOCATION );
+
+ if (xKey.is())
+ {
+ xKey->setAsciiValue(locationUrl);
+ }
+
+ // update ACTIVATOR entry
+ xKey = xImplKey->createKey( slash_UNO_slash_ACTIVATOR );
+
+ if (xKey.is())
+ {
+ xKey->setAsciiValue(implementationLoaderUrl);
+ }
+
+ xKey = xImplKey->openKey( slash_UNO_slash_SERVICES );
+
+ if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST))
+ {
+ // update link entries in REGISTRY_LINKS section
+ const Sequence<OUString> linkNames = xKey->getAsciiListValue();
+
+ for (const OUString& rLinkName : linkNames)
+ {
+ prepareLink(xDest, xImplKey, rLinkName);
+ }
+ }
+
+ insert_singletons( xDest, xImplKey, xContext );
+ }
+}
+
+
+void findImplementations( const Reference < XRegistryKey > & xSource,
+ std::vector<OUString>& implNames)
+{
+ bool isImplKey = false;
+
+ try
+ {
+ Reference < XRegistryKey > xKey = xSource->openKey(
+ slash_UNO_slash_SERVICES );
+
+ if (xKey.is() && xKey->getKeyNames().hasElements())
+ {
+ isImplKey = true;
+
+ OUString implName = xSource->getKeyName().copy(1).replace('/', '.');
+ sal_Int32 firstDot = implName.indexOf('.');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ implNames.push_back(implName);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+
+ if (isImplKey) return;
+
+ try
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ for (const Reference < XRegistryKey >& rSubKey : subKeys)
+ {
+ findImplementations(rSubKey, implNames);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+}
+
+
+class ImplementationRegistration
+ : public WeakImplHelper< XImplementationRegistration2, XServiceInfo, XInitialization >
+{
+public:
+ explicit ImplementationRegistration( const Reference < XComponentContext > & rSMgr );
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XImplementationRegistration
+ virtual void SAL_CALL registerImplementation(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const Reference < XSimpleRegistry > & xReg) override;
+
+ virtual sal_Bool SAL_CALL revokeImplementation(
+ const OUString& location,
+ const Reference < XSimpleRegistry >& xReg) override;
+
+ virtual Sequence< OUString > SAL_CALL getImplementations(
+ const OUString& implementationLoader,
+ const OUString& location) override;
+ virtual Sequence< OUString > SAL_CALL checkInstantiation(
+ const OUString& implementationName) override;
+
+ // XImplementationRegistration2
+ virtual void SAL_CALL registerImplementationWithLocation(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const OUString& registeredLocation,
+ const Reference < XSimpleRegistry > & xReg) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+private: // helper methods
+ void prepareRegister(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const OUString& registeredLocation,
+ const Reference < XSimpleRegistry > & xReg);
+ // throw( CannotRegisterImplementationException, RuntimeException )
+
+ static void doRegister( const Reference < XMultiComponentFactory >& xSMgr,
+ const Reference < XComponentContext > &xCtx,
+ const Reference < XImplementationLoader >& xAct,
+ const Reference < XSimpleRegistry >& xDest,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl);
+ /* throw ( InvalidRegistryException,
+ MergeConflictException,
+ CannotRegisterImplementationException, RuntimeException ) */
+
+ static void doRevoke( const Reference < XSimpleRegistry >& xDest,
+ std::u16string_view locationUrl );
+ // throw( InvalidRegistryException, RuntimeException )
+ Reference< XSimpleRegistry > getRegistryFromServiceManager() const;
+
+ static Reference< XSimpleRegistry > createTemporarySimpleRegistry(
+ const Reference< XMultiComponentFactory > &rSMgr,
+ const Reference < XComponentContext > & rCtx );
+
+private: // members
+ Reference < XMultiComponentFactory > m_xSMgr;
+ Reference < XComponentContext > m_xCtx;
+};
+
+
+// ImplementationRegistration()
+
+ImplementationRegistration::ImplementationRegistration( const Reference < XComponentContext > & xCtx )
+ : m_xSMgr( xCtx->getServiceManager() )
+ , m_xCtx( xCtx )
+{}
+
+// XServiceInfo
+OUString ImplementationRegistration::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.ImplementationRegistration";
+}
+
+// XServiceInfo
+sal_Bool ImplementationRegistration::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > ImplementationRegistration::getSupportedServiceNames()
+{
+ return { "com.sun.star.registry.ImplementationRegistration" };
+}
+
+Reference< XSimpleRegistry > ImplementationRegistration::getRegistryFromServiceManager() const
+{
+ Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
+ Reference < XSimpleRegistry > xRegistry;
+
+ if( xPropSet.is() ) {
+
+ try { // the implementation does not support XIntrospectionAccess !
+
+ Any aAny = xPropSet->getPropertyValue( Registry );
+
+ if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aAny >>= xRegistry;
+ }
+ }
+ catch( UnknownPropertyException & ) {
+ // empty reference is error signal !
+ }
+ }
+
+ return xRegistry;
+}
+
+
+// XInitialization
+
+void ImplementationRegistration::initialize(
+ const css::uno::Sequence< css::uno::Any >& aArgs )
+{
+
+ if( aArgs.getLength() != 4 ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() expects 4 parameters, got " + OUString::number( aArgs.getLength() ),
+ Reference<XInterface > (), 0 );
+ }
+
+ Reference< XImplementationLoader > rLoader;
+ OUString loaderServiceName;
+ OUString locationUrl;
+ Reference< XSimpleRegistry > rReg;
+
+ // 1st argument : An instance of an implementation loader
+ if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aArgs.getConstArray()[0] >>= rLoader;
+ }
+ if( !rLoader.is()) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid first parameter,"
+ "expected " + cppu::UnoType<decltype(rLoader)>::get().getTypeName() +
+ ", got " + aArgs.getConstArray()[0].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 2nd argument : The service name of the loader. This name is written into the registry
+ if( aArgs.getConstArray()[1].getValueType().getTypeClass() == TypeClass_STRING ) {
+ aArgs.getConstArray()[1] >>= loaderServiceName;
+ }
+ if( loaderServiceName.isEmpty() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid second parameter,"
+ "expected string, got " + aArgs.getConstArray()[1].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 3rd argument : The file name of the dll, that contains the loader
+ if( aArgs.getConstArray()[2].getValueType().getTypeClass() == TypeClass_STRING ) {
+ aArgs.getConstArray()[2] >>= locationUrl;
+ }
+ if( locationUrl.isEmpty() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid third parameter,"
+ "expected string, got " + aArgs.getConstArray()[2].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 4th argument : The registry, the service should be written to
+ if( aArgs.getConstArray()[3].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aArgs.getConstArray()[3] >>= rReg;
+ }
+
+ if( !rReg.is() ) {
+ rReg = getRegistryFromServiceManager();
+ if( !rReg.is() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid fourth parameter,"
+ "expected " + cppu::UnoType<decltype(rReg)>::get().getTypeName() +
+ ", got " + aArgs.getConstArray()[3].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+ }
+
+ doRegister(m_xSMgr, m_xCtx, rLoader , rReg, loaderServiceName , locationUrl, locationUrl);
+}
+
+
+// virtual function registerImplementationWithLocation of XImplementationRegistration2
+
+void ImplementationRegistration::registerImplementationWithLocation(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+{
+ prepareRegister(
+ implementationLoaderUrl, locationUrl, registeredLocationUrl, xReg);
+}
+
+// helper function
+void ImplementationRegistration::prepareRegister(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+ // throw( CannotRegisterImplementationException, RuntimeException )
+{
+ OUString activatorName;
+
+ if (!implementationLoaderUrl.isEmpty())
+ {
+ activatorName = implementationLoaderUrl.getToken(0, ':');
+ } else
+ {
+ // check locationUrl to find out what kind of loader is needed
+ // set implLoaderUrl
+ }
+
+ if( !m_xSMgr.is() ) {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "no componentcontext available to instantiate loader" );
+ }
+
+ try
+ {
+ Reference < XImplementationLoader > xAct(
+ m_xSMgr->createInstanceWithContext(activatorName, m_xCtx) , UNO_QUERY );
+ if (!xAct.is())
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() - The service "
+ + activatorName + " cannot be instantiated" );
+ }
+
+ Reference < XSimpleRegistry > xRegistry;
+
+ if (xReg.is())
+ {
+ // registry supplied by user
+ xRegistry = xReg;
+ }
+ else
+ {
+ xRegistry = getRegistryFromServiceManager();
+ }
+
+ if ( xRegistry.is())
+ {
+ doRegister(m_xSMgr, m_xCtx, xAct, xRegistry, implementationLoaderUrl,
+ locationUrl, registeredLocationUrl);
+ }
+
+ }
+ catch( CannotRegisterImplementationException & )
+ {
+ throw;
+ }
+ catch( const InvalidRegistryException & e )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "InvalidRegistryException during registration (" + e.Message + ")" );
+ }
+ catch( const MergeConflictException & e )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "MergeConflictException during registration (" + e.Message + ")" );
+ }
+
+}
+
+
+// virtual function registerImplementation of XImplementationRegistration
+
+void ImplementationRegistration::registerImplementation(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+{
+ prepareRegister(implementationLoaderUrl, locationUrl, locationUrl, xReg);
+}
+
+
+// virtual function revokeImplementation of XImplementationRegistration
+
+sal_Bool ImplementationRegistration::revokeImplementation(const OUString& location,
+ const Reference < XSimpleRegistry >& xReg)
+{
+ bool ret = false;
+
+ Reference < XSimpleRegistry > xRegistry;
+
+ if (xReg.is()) {
+ xRegistry = xReg;
+ }
+ else {
+ Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
+ if( xPropSet.is() ) {
+ try {
+ Any aAny = xPropSet->getPropertyValue( Registry );
+
+ if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
+ {
+ aAny >>= xRegistry;
+ }
+ }
+ catch ( UnknownPropertyException & ) {
+ }
+ }
+ }
+
+ if (xRegistry.is())
+ {
+ try
+ {
+ doRevoke(xRegistry, location);
+ ret = true;
+ }
+ catch( InvalidRegistryException & )
+ {
+ // no way to transport the error, as no exception is specified and a runtime
+ // exception is not appropriate.
+ OSL_FAIL( "InvalidRegistryException during revokeImplementation" );
+ }
+ }
+
+ return ret;
+}
+
+
+// virtual function getImplementations of XImplementationRegistration
+
+Sequence< OUString > ImplementationRegistration::getImplementations(
+ const OUString & implementationLoaderUrl,
+ const OUString & locationUrl)
+{
+ OUString activatorName;
+
+ if (!implementationLoaderUrl.isEmpty())
+ {
+ activatorName = implementationLoaderUrl.getToken(0, ':');
+ } else
+ {
+ // check locationUrl to find out what kind of loader is needed
+ // set implementationLoaderUrl
+ }
+
+ if( m_xSMgr.is() ) {
+
+ Reference < XImplementationLoader > xAct(
+ m_xSMgr->createInstanceWithContext( activatorName, m_xCtx ), UNO_QUERY );
+
+ if (xAct.is())
+ {
+
+ Reference < XSimpleRegistry > xReg =
+ createTemporarySimpleRegistry( m_xSMgr, m_xCtx);
+
+ if (xReg.is())
+ {
+ try
+ {
+ xReg->open(OUString() /* in mem */, false, true);
+ Reference < XRegistryKey > xImpl;
+
+ { // only necessary for deleting the temporary variable of rootkey
+ xImpl = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
+ }
+ if (xAct->writeRegistryInfo(xImpl, implementationLoaderUrl, locationUrl))
+ {
+ std::vector<OUString> implNames;
+
+ findImplementations(xImpl, implNames);
+
+ if (!implNames.empty())
+ {
+ Sequence<OUString> seqImpl(comphelper::containerToSequence(implNames));
+ xImpl->closeKey();
+ return seqImpl;
+ }
+ }
+
+ xImpl->closeKey();
+ }
+ catch(MergeConflictException&)
+ {
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+ }
+ }
+ }
+
+ return Sequence<OUString>();
+}
+
+
+// virtual function checkInstantiation of XImplementationRegistration
+
+Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&)
+{
+ OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" );
+ return Sequence<OUString>();
+}
+
+
+// helper function doRegistration
+
+
+void ImplementationRegistration::doRevoke(
+ const Reference < XSimpleRegistry >& xDest,
+ std::u16string_view locationUrl)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if( !xDest.is() )
+ return;
+
+ std::vector<OUString> aNames;
+
+ Reference < XRegistryKey > xRootKey( xDest->getRootKey() );
+
+ Reference < XRegistryKey > xKey =
+ xRootKey->openKey( slash_IMPLEMENTATIONS );
+ if (xKey.is() && xKey->isValid())
+ {
+ deleteAllImplementations(xDest, xKey, locationUrl, aNames);
+ }
+
+ xKey = xRootKey->openKey( slash_SERVICES );
+ if (xKey.is())
+ {
+ for (auto const& name : aNames)
+ {
+ deleteAllServiceEntries(xDest, xKey, name);
+ }
+ }
+
+ xKey = xRootKey->openKey( "/SINGLETONS" );
+ if (xKey.is() && xKey->isValid())
+ {
+ delete_all_singleton_entries( xKey, aNames );
+ }
+
+ if (xRootKey.is())
+ xRootKey->closeKey();
+ if (xKey.is() && xKey->isValid() )
+ xKey->closeKey();
+}
+
+void ImplementationRegistration::doRegister(
+ const Reference< XMultiComponentFactory > & xSMgr,
+ const Reference< XComponentContext > &xCtx,
+ const Reference < XImplementationLoader > & xAct,
+ const Reference < XSimpleRegistry >& xDest,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl)
+ /* throw ( InvalidRegistryException,
+ MergeConflictException,
+ CannotRegisterImplementationException, RuntimeException ) */
+{
+ Reference < XSimpleRegistry > xReg =
+ createTemporarySimpleRegistry( xSMgr, xCtx );
+ Reference < XRegistryKey > xSourceKey;
+
+ if (!(xAct.is() && xReg.is() && xDest.is()))
+ return;
+
+ try
+ {
+ xReg->open(OUString() /* in mem */, false, true);
+
+ { // only necessary for deleting the temporary variable of rootkey
+ xSourceKey = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
+ }
+
+ bool bSuccess =
+ xAct->writeRegistryInfo(xSourceKey, implementationLoaderUrl, locationUrl);
+ if ( !bSuccess )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::doRegistration() component registration signaled failure" );
+ }
+
+ prepareRegistry(xDest, xSourceKey, implementationLoaderUrl, registeredLocationUrl, xCtx);
+
+ xSourceKey->closeKey();
+
+ xSourceKey = xReg->getRootKey();
+ Reference < XRegistryKey > xDestKey = xDest->getRootKey();
+ stoc_impreg::mergeKeys( xDestKey, xSourceKey );
+ xDestKey->closeKey();
+ xSourceKey->closeKey();
+
+
+ // Cleanup Source registry.
+ if ( xSourceKey->isValid() )
+ xSourceKey->closeKey();
+ }
+ catch(CannotRegisterImplementationException&)
+ {
+ if ( xSourceKey->isValid() )
+ xSourceKey->closeKey();
+ // and throw again
+ throw;
+ }
+}
+
+
+Reference< XSimpleRegistry > ImplementationRegistration::createTemporarySimpleRegistry(
+ const Reference< XMultiComponentFactory > &rSMgr,
+ const Reference < XComponentContext > & xCtx)
+{
+
+ Reference < XSimpleRegistry > xReg(
+ rSMgr->createInstanceWithContext(
+ com_sun_star_registry_SimpleRegistry, xCtx ),
+ UNO_QUERY);
+ OSL_ASSERT( xReg.is() );
+ return xReg;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_ImplementationRegistration_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ImplementationRegistration(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/mergekeys.cxx b/stoc/source/implementationregistration/mergekeys.cxx
new file mode 100644
index 000000000..da7da509e
--- /dev/null
+++ b/stoc/source/implementationregistration/mergekeys.cxx
@@ -0,0 +1,176 @@
+/* -*- 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 <vector>
+
+#include <osl/diagnose.h>
+
+#include <com/sun/star/registry/XRegistryKey.hpp>
+
+#include "mergekeys.hxx"
+
+using namespace ::osl;
+using namespace css::uno;
+using namespace ::com::sun::star;
+
+namespace stoc_impreg
+{
+
+namespace {
+
+struct Link
+{
+ OUString m_name;
+ OUString m_target;
+
+ Link( OUString const & name, OUString const & target )
+ : m_name( name )
+ , m_target( target )
+ {}
+};
+
+}
+
+typedef ::std::vector< Link > t_links;
+
+
+static void mergeKeys(
+ Reference< registry::XRegistryKey > const & xDest,
+ Reference< registry::XRegistryKey > const & xSource,
+ t_links & links )
+ // throw( registry::InvalidRegistryException, registry::MergeConflictException, RuntimeException )
+{
+ if (!xSource.is() || !xSource->isValid()) {
+ throw registry::InvalidRegistryException(
+ "source key is null or invalid!" );
+ }
+ if (!xDest.is() || !xDest->isValid()) {
+ throw registry::InvalidRegistryException(
+ "destination key is null or invalid!" );
+ }
+
+ // write value
+ switch (xSource->getValueType())
+ {
+ case registry::RegistryValueType_NOT_DEFINED:
+ break;
+ case registry::RegistryValueType_LONG:
+ xDest->setLongValue( xSource->getLongValue() );
+ break;
+ case registry::RegistryValueType_ASCII:
+ xDest->setAsciiValue( xSource->getAsciiValue() );
+ break;
+ case registry::RegistryValueType_STRING:
+ xDest->setStringValue( xSource->getStringValue() );
+ break;
+ case registry::RegistryValueType_BINARY:
+ xDest->setBinaryValue( xSource->getBinaryValue() );
+ break;
+ case registry::RegistryValueType_LONGLIST:
+ xDest->setLongListValue( xSource->getLongListValue() );
+ break;
+ case registry::RegistryValueType_ASCIILIST:
+ xDest->setAsciiListValue( xSource->getAsciiListValue() );
+ break;
+ case registry::RegistryValueType_STRINGLIST:
+ xDest->setStringListValue( xSource->getStringListValue() );
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ // sub keys
+ Sequence< OUString > sourceKeys( xSource->getKeyNames() );
+ OUString const * pSourceKeys = sourceKeys.getConstArray();
+ for ( sal_Int32 nPos = sourceKeys.getLength(); nPos--; )
+ {
+ // key name
+ OUString name( pSourceKeys[ nPos ] );
+ sal_Int32 nSlash = name.lastIndexOf( '/' );
+ if (nSlash >= 0)
+ {
+ name = name.copy( nSlash +1 );
+ }
+
+ if (xSource->getKeyType( name ) == registry::RegistryKeyType_KEY)
+ {
+ // try to open existing dest key or create new one
+ Reference< registry::XRegistryKey > xDestKey( xDest->createKey( name ) );
+ Reference< registry::XRegistryKey > xSourceKey( xSource->openKey( name ) );
+ mergeKeys( xDestKey, xSourceKey, links );
+ xSourceKey->closeKey();
+ xDestKey->closeKey();
+ }
+ else // link
+ {
+ // remove existing key
+ Reference< registry::XRegistryKey > xDestKey( xDest->openKey( name ) );
+ if (xDestKey.is() && xDestKey->isValid()) // something to remove
+ {
+ xDestKey->closeKey();
+ if (xDest->getKeyType( name ) == registry::RegistryKeyType_LINK)
+ {
+ xDest->deleteLink( name );
+ }
+ else
+ {
+ xDest->deleteKey( name );
+ }
+ }
+
+ links.push_back( Link(
+ pSourceKeys[ nPos ], // abs path
+ xSource->getResolvedName( name ) // abs resolved name
+ ) );
+ }
+ }
+}
+
+
+void mergeKeys(
+ Reference< registry::XRegistryKey > const & xDest,
+ Reference< registry::XRegistryKey > const & xSource )
+ // throw( registry::InvalidRegistryException, registry::MergeConflictException, RuntimeException )
+{
+ if (!xDest.is() || !xDest->isValid()) {
+ throw registry::InvalidRegistryException(
+ "destination key is null or invalid!" );
+ }
+ if (xDest->isReadOnly())
+ {
+ throw registry::InvalidRegistryException(
+ "destination registry is read-only! cannot merge!" );
+ }
+
+ t_links links;
+ links.reserve( 16 );
+ mergeKeys( xDest, xSource, links );
+
+ for ( size_t nPos = links.size(); nPos--; )
+ {
+ Link const & r = links[ nPos ];
+ OSL_VERIFY( xDest->createLink( r.m_name, r.m_target ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/mergekeys.hxx b/stoc/source/implementationregistration/mergekeys.hxx
new file mode 100644
index 000000000..3f54e5712
--- /dev/null
+++ b/stoc/source/implementationregistration/mergekeys.hxx
@@ -0,0 +1,46 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_STOC_SOURCE_IMPLEMENTATIONREGISTRATION_MERGEKEYS_HXX
+#define INCLUDED_STOC_SOURCE_IMPLEMENTATIONREGISTRATION_MERGEKEYS_HXX
+
+#include <sal/config.h>
+#include <sal/types.h>
+
+namespace com::sun::star::registry {
+ class XRegistryKey;
+}
+namespace com::sun::star::uno { template <typename > class Reference; }
+
+namespace stoc_impreg {
+
+// throws css::registry::InvalidRegistryException,
+// css::registry::MergeConflictException,
+// css::uno::RuntimeException:
+void mergeKeys(
+ css::uno::Reference< css::registry::XRegistryKey >
+ const & xDest,
+ css::uno::Reference< css::registry::XRegistryKey >
+ const & xSource);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/inspect/introspection.component b/stoc/source/inspect/introspection.component
new file mode 100644
index 000000000..84e121fad
--- /dev/null
+++ b/stoc/source/inspect/introspection.component
@@ -0,0 +1,28 @@
+<?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.Introspection"
+ constructor="com_sun_star_comp_stoc_Introspection_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.beans.Introspection"/>
+ <singleton name="com.sun.star.beans.theIntrospection"/>
+ </implementation>
+</component>
diff --git a/stoc/source/inspect/introspection.cxx b/stoc/source/inspect/introspection.cxx
new file mode 100644
index 000000000..1a92d5b4c
--- /dev/null
+++ b/stoc/source/inspect/introspection.cxx
@@ -0,0 +1,2420 @@
+/* -*- 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 <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <limits>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+#include <com/sun/star/lang/NoSuchMethodException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/XIdlClass.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XIntrospection.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/beans/XExactName.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <unordered_map>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::container;
+using namespace css::beans;
+using namespace css::beans::PropertyAttribute;
+using namespace css::beans::PropertyConcept;
+using namespace css::beans::MethodConcept;
+using namespace cppu;
+using namespace osl;
+
+namespace
+{
+
+typedef WeakImplHelper< XIntrospectionAccess, XMaterialHolder, XExactName,
+ XPropertySet, XFastPropertySet, XPropertySetInfo,
+ XNameContainer, XIndexContainer, XEnumerationAccess,
+ XIdlArray, XUnoTunnel > IntrospectionAccessHelper;
+
+
+// Special value for Method-Concept, to be able to mark "normal" functions
+#define MethodConcept_NORMAL_IMPL 0x80000000
+
+
+// Method to assert, if a class is derived from another class
+bool isDerivedFrom( const Reference<XIdlClass>& xToTestClass, const Reference<XIdlClass>& xDerivedFromClass )
+{
+ const Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();
+
+ return std::any_of(aClassesSeq.begin(), aClassesSeq.end(),
+ [&xDerivedFromClass](const Reference<XIdlClass>& rxClass) {
+ return xDerivedFromClass->equals( rxClass )
+ || isDerivedFrom( rxClass, xDerivedFromClass );
+ });
+}
+
+
+// *** Classification of Properties (no enum, to be able to use Sequence) ***
+// Properties from a PropertySet-Interface
+#define MAP_PROPERTY_SET 0
+// Properties from Fields
+#define MAP_FIELD 1
+// Properties that get described with get/set methods
+#define MAP_GETSET 2
+// Properties with only a set method
+#define MAP_SETONLY 3
+
+
+// Increments by which the size of sequences get adjusted
+#define ARRAY_SIZE_STEP 20
+
+
+//*** IntrospectionAccessStatic_Impl ***
+
+// Equals to the old IntrospectionAccessImpl, forms now a static
+// part of the new Instance-related ImplIntrospectionAccess
+
+// Hashtable for the search of names
+typedef std::unordered_map
+<
+ OUString,
+ sal_Int32
+>
+IntrospectionNameMap;
+
+
+// Hashtable to assign exact names to the Lower-Case
+// converted names, for the support of XExactName
+typedef std::unordered_map
+<
+ OUString,
+ OUString
+>
+LowerToExactNameMap;
+
+
+class IntrospectionAccessStatic_Impl: public salhelper::SimpleReferenceObject
+{
+ friend class Implementation;
+ friend class ImplIntrospectionAccess;
+
+ // Holding CoreReflection
+ Reference< XIdlReflection > mxCoreReflection;
+
+ // InterfaceSequences, to save additional information in a property
+ // for example the Field at MAP_FIELD, the get/set-Methods at MAP_GETSET, et cetera
+ std::vector< Reference<XInterface> > aInterfaceSeq1;
+ std::vector< Reference<XInterface> > aInterfaceSeq2;
+
+ // Hashtables for names
+ IntrospectionNameMap maPropertyNameMap;
+ IntrospectionNameMap maMethodNameMap;
+ LowerToExactNameMap maLowerToExactNameMap;
+
+ // Vector of all Properties, also for delivering from getProperties()
+ std::vector<Property> maAllPropertySeq;
+
+ // Mapping of properties to Access-Types
+ std::vector<sal_Int16> maMapTypeSeq;
+
+ // Classification of found methods
+ std::vector<sal_Int32> maPropertyConceptSeq;
+
+ // Number of Properties
+ sal_Int32 mnPropCount;
+
+ // Number of Properties, which are assigned to particular concepts
+ //sal_Int32 mnDangerousPropCount;
+ sal_Int32 mnPropertySetPropCount;
+ sal_Int32 mnAttributePropCount;
+ sal_Int32 mnMethodPropCount;
+
+ // Flags which indicate if various interfaces are present
+ bool mbFastPropSet;
+ bool mbElementAccess;
+ bool mbNameAccess;
+ bool mbNameReplace;
+ bool mbNameContainer;
+ bool mbIndexAccess;
+ bool mbIndexReplace;
+ bool mbIndexContainer;
+ bool mbEnumerationAccess;
+ bool mbIdlArray;
+ bool mbUnoTunnel;
+
+ // Original handles of FastPropertySets
+ std::unique_ptr<sal_Int32[]> mpOrgPropertyHandleArray;
+
+ // MethodSequence, that accepts all methods
+ std::vector< Reference<XIdlMethod> > maAllMethodSeq;
+
+ // Classification of found methods
+ std::vector<sal_Int32> maMethodConceptSeq;
+
+ // Number of methods
+ sal_Int32 mnMethCount;
+
+ // Sequence of Listener, that can be registered
+ std::vector< Type > maSupportedListenerSeq;
+
+ // Helper-methods for adjusting sizes of Sequences
+ void checkPropertyArraysSize( sal_Int32 iNextIndex );
+ static void checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq, std::vector<Reference<XInterface>>& rInterfaceVec,
+ sal_Int32 iNextIndex );
+
+public:
+ explicit IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ );
+ sal_Int32 getPropertyIndex( const OUString& aPropertyName ) const;
+ sal_Int32 getMethodIndex( const OUString& aMethodName ) const;
+
+ // Methods of XIntrospectionAccess (OLD, now only Impl)
+ void setPropertyValue(const Any& obj, const OUString& aPropertyName, const Any& aValue) const;
+// void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const;
+ Any getPropertyValue(const Any& obj, const OUString& aPropertyName) const;
+ void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValue) const;
+// void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const;
+ Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const;
+
+ const std::vector<Property>& getProperties() const { return maAllPropertySeq; }
+ const std::vector< Reference<XIdlMethod> >& getMethods() const { return maAllMethodSeq; }
+ const std::vector< Type >& getSupportedListeners() const { return maSupportedListenerSeq; }
+ const std::vector<sal_Int32>& getPropertyConcepts() const { return maPropertyConceptSeq; }
+ const std::vector<sal_Int32>& getMethodConcepts() const { return maMethodConceptSeq; }
+};
+
+
+// Ctor
+IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ )
+ : mxCoreReflection( xCoreReflection_ )
+{
+ aInterfaceSeq1.resize( ARRAY_SIZE_STEP );
+ aInterfaceSeq2.resize( ARRAY_SIZE_STEP );
+
+ // Property-Data
+ maAllPropertySeq.resize( ARRAY_SIZE_STEP );
+ maMapTypeSeq.resize( ARRAY_SIZE_STEP );
+ maPropertyConceptSeq.resize( ARRAY_SIZE_STEP );
+
+ mbFastPropSet = false;
+ mbElementAccess = false;
+ mbNameAccess = false;
+ mbNameReplace = false;
+ mbNameContainer = false;
+ mbIndexAccess = false;
+ mbIndexReplace = false;
+ mbIndexContainer = false;
+ mbEnumerationAccess = false;
+ mbIdlArray = false;
+ mbUnoTunnel = false;
+
+ mpOrgPropertyHandleArray = nullptr;
+
+ mnPropCount = 0;
+ //mnDangerousPropCount = 0;
+ mnPropertySetPropCount = 0;
+ mnAttributePropCount = 0;
+ mnMethodPropCount = 0;
+
+ // Method-Data
+ mnMethCount = 0;
+}
+
+sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const
+{
+ auto aIt = maPropertyNameMap.find(aPropertyName);
+ if (aIt != maPropertyNameMap.end())
+ return aIt->second;
+
+ return -1;
+}
+
+sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const
+{
+ auto aIt = maMethodNameMap.find(aMethodName);
+ if (aIt != maMethodNameMap.end())
+ {
+ return aIt->second;
+ }
+
+ // #95159 Check if full qualified name matches
+ sal_Int32 nSearchFrom = aMethodName.getLength();
+ while( true )
+ {
+ // Strategy: Search back until the first '_' is found
+ sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom );
+ if( nFound == -1 )
+ break;
+
+ OUString aPureMethodName = aMethodName.copy( nFound + 1 );
+
+ aIt = maMethodNameMap.find( aPureMethodName );
+ if (aIt != maMethodNameMap.end())
+ {
+ // Check if it can be a type?
+ // Problem: Does not work if package names contain _ ?!
+ OUString aStr = aMethodName.copy( 0, nFound );
+ OUString aTypeName = aStr.replace( '_', '.' );
+ Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName );
+ if( xClass.is() )
+ {
+ // If this is a valid class it could be the right method
+
+ // Could be the right method, type has to be checked
+ const sal_Int32 iHashResult = aIt->second;
+
+ const Reference<XIdlMethod> xMethod = maAllMethodSeq[iHashResult];
+
+ Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass();
+ if( xClass->equals( xMethClass ) )
+ {
+ return iHashResult;
+ }
+ else
+ {
+ // Could also be another method with the same name
+ // Iterate over all methods
+ size_t nLen = maAllMethodSeq.size();
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ const Reference<XIdlMethod> xMethod2 = maAllMethodSeq[ i ];
+ if( xMethod2->getName() == aPureMethodName )
+ {
+ Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();
+
+ if( xClass->equals( xMethClass2 ) )
+ {
+ return i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nSearchFrom = nFound - 1;
+ if( nSearchFrom < 0 )
+ break;
+ }
+ return -1;
+}
+
+void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const OUString& aPropertyName, const Any& aValue ) const
+//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const OUString& aPropertyName, const Any& aValue ) const
+{
+ sal_Int32 i = getPropertyIndex( aPropertyName );
+ if( i == -1 )
+ throw UnknownPropertyException(aPropertyName);
+ setPropertyValueByIndex( obj, i, aValue );
+}
+
+void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
+//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
+{
+ // Is the passed object something that fits?
+ Reference<XInterface> xInterface;
+ if( !(obj >>= xInterface) )
+ {
+ TypeClass eObjType = obj.getValueType().getTypeClass();
+ if( nSequenceIndex >= mnPropCount)
+ throw IllegalArgumentException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), index > propertyCount, " +
+ OUString::number(nSequenceIndex) + " > " + OUString::number(mnPropCount),
+ Reference<XInterface>(), 0);
+ if( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION )
+ throw IllegalArgumentException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), expected struct or exception, got" +
+ obj.getValueType().getTypeName(), Reference<XInterface>(), 0);
+ }
+
+ // Test flags
+ if( (maAllPropertySeq[ nSequenceIndex ].Attributes & READONLY) != 0 )
+ {
+ throw UnknownPropertyException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), property at index " + OUString::number(nSequenceIndex) + " is readonly");
+ }
+
+ switch( maMapTypeSeq[ nSequenceIndex ] )
+ {
+ case MAP_PROPERTY_SET:
+ {
+ // Get Property
+ const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
+
+ // Convert Interface-Parameter to the correct type
+ bool bUseCopy = false;
+ Any aRealValue;
+
+ if( auto valInterface = o3tl::tryAccess<
+ css::uno::Reference<css::uno::XInterface>>(aValue) )
+ {
+ Type aPropType = rProp.Type;
+ OUString aTypeName( aPropType.getTypeName() );
+ Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName );
+ //Reference<XIdlClass> xPropClass = rProp.Type;
+ if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE )
+ {
+ if( valInterface->is() )
+ {
+ //Any queryInterface( const Type& rType );
+ aRealValue = (*valInterface)->queryInterface( aPropType );
+ if( aRealValue.hasValue() )
+ bUseCopy = true;
+ }
+ }
+ }
+
+ // Do we have a FastPropertySet and a valid Handle?
+ // CAUTION: At this point we exploit that the PropertySet
+ // gets queried at the beginning of the Introspection-Process.
+ sal_Int32 nOrgHandle;
+ if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
+ {
+ // Retrieve PropertySet-Interface
+ Reference<XFastPropertySet> xFastPropSet =
+ Reference<XFastPropertySet>::query( xInterface );
+ if( xFastPropSet.is() )
+ {
+ xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ }
+ }
+ // else take the normal one
+ else
+ {
+ // Retrieve PropertySet-Interface
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( xInterface );
+ if( xPropSet.is() )
+ {
+ xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ }
+ }
+ }
+ break;
+
+ case MAP_FIELD:
+ {
+ Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ Reference<XIdlField2> xField2(xField, UNO_QUERY);
+ if( xField2.is() )
+ {
+ xField2->set( const_cast<Any&>(obj), aValue );
+ // IllegalArgumentException
+ // NullPointerException
+ } else
+ if( xField.is() )
+ {
+ xField->set( obj, aValue );
+ // IllegalArgumentException
+ // NullPointerException
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ }
+ }
+ break;
+
+ case MAP_GETSET:
+ case MAP_SETONLY:
+ {
+ // Fetch set method
+ Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq2[ nSequenceIndex ].get());
+ if( xMethod.is() )
+ {
+ Sequence<Any> args( 1 );
+ args.getArray()[0] = aValue;
+ xMethod->invoke( obj, args );
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ }
+ }
+ break;
+ }
+}
+
+Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const OUString& aPropertyName ) const
+{
+ sal_Int32 i = getPropertyIndex( aPropertyName );
+ if( i != -1 )
+ return getPropertyValueByIndex( obj, i );
+
+ throw UnknownPropertyException(aPropertyName);
+}
+
+Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const
+{
+ Any aRet;
+
+ // Is there anything suitable in the passed object?
+ Reference<XInterface> xInterface;
+ if( !(obj >>= xInterface) )
+ {
+ TypeClass eObjType = obj.getValueType().getTypeClass();
+ if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+
+ switch( maMapTypeSeq[ nSequenceIndex ] )
+ {
+ case MAP_PROPERTY_SET:
+ {
+ // Acquire property
+ const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
+
+ // Do we have a FastPropertySet and a valid handle?
+ // NOTE: At this point is exploited that the PropertySet
+ // is queried at the beginning of introspection process.
+ sal_Int32 nOrgHandle;
+ if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
+ {
+ // Fetch the PropertySet interface
+ Reference<XFastPropertySet> xFastPropSet =
+ Reference<XFastPropertySet>::query( xInterface );
+ if( xFastPropSet.is() )
+ {
+ aRet = xFastPropSet->getFastPropertyValue( nOrgHandle);
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ return aRet;
+ }
+ }
+ // Otherwise use the normal one
+ else
+ {
+ // Fetch the PropertySet interface
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( xInterface );
+ if( xPropSet.is() )
+ {
+ aRet = xPropSet->getPropertyValue( rProp.Name );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ return aRet;
+ }
+ }
+ }
+ break;
+
+ case MAP_FIELD:
+ {
+ Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ if( xField.is() )
+ {
+ aRet = xField->get( obj );
+ // IllegalArgumentException
+ // NullPointerException
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+ break;
+
+ case MAP_GETSET:
+ {
+ // Fetch get method
+ Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ if( xMethod.is() )
+ {
+ Sequence<Any> args;
+ aRet = xMethod->invoke( obj, args );
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+ break;
+
+ case MAP_SETONLY:
+ // Get method does not exist
+ // throw WriteOnlyPropertyException();
+ return aRet;
+ }
+ return aRet;
+}
+
+
+// Helper method to adjust the size of the vectors
+void IntrospectionAccessStatic_Impl::checkPropertyArraysSize( sal_Int32 iNextIndex )
+{
+ sal_Int32 nLen = static_cast<sal_Int32>(maAllPropertySeq.size());
+ if( iNextIndex >= nLen )
+ {
+ maAllPropertySeq.resize( nLen + ARRAY_SIZE_STEP );
+ maMapTypeSeq.resize( nLen + ARRAY_SIZE_STEP );
+ maPropertyConceptSeq.resize( nLen + ARRAY_SIZE_STEP );
+ }
+}
+
+void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq,
+ std::vector<Reference<XInterface>>& rInterfaceVec, sal_Int32 iNextIndex )
+{
+ sal_Int32 nLen = rSeq.size();
+ if( iNextIndex >= nLen )
+ {
+ // Synchronize new size with ARRAY_SIZE_STEP
+ sal_Int32 nMissingSize = iNextIndex - nLen + 1;
+ sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1;
+ sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP;
+
+ rSeq.resize( nNewSize );
+ rInterfaceVec = rSeq;
+ }
+}
+
+
+//*** ImplIntrospectionAccess ***
+
+
+// New Impl class as part of the introspection conversion to instance-bound
+// Introspection with property access via XPropertySet. The old class
+// ImplIntrospectionAccess lives on as IntrospectionAccessStatic_Impl
+class ImplIntrospectionAccess : public IntrospectionAccessHelper
+{
+ friend class Implementation;
+
+ // Object under examination
+ Any maInspectedObject;
+
+ // As interface
+ Reference<XInterface> mxIface;
+
+ // Static introspection data
+ rtl::Reference< IntrospectionAccessStatic_Impl > mpStaticImpl;
+
+ // Last Sequence that came with getProperties (optimization)
+ Sequence<Property> maLastPropertySeq;
+ sal_Int32 mnLastPropertyConcept;
+
+ // Last Sequence that came with getMethods (optimization)
+ Sequence<Reference<XIdlMethod> > maLastMethodSeq;
+ sal_Int32 mnLastMethodConcept;
+
+ // Guards the caching of queried interfaces
+ std::mutex m_aMutex;
+
+ // Original interfaces of the objects
+ Reference<XElementAccess> mxObjElementAccess;
+ Reference<XNameContainer> mxObjNameContainer;
+ Reference<XNameReplace> mxObjNameReplace;
+ Reference<XNameAccess> mxObjNameAccess;
+ Reference<XIndexContainer> mxObjIndexContainer;
+ Reference<XIndexReplace> mxObjIndexReplace;
+ Reference<XIndexAccess> mxObjIndexAccess;
+ Reference<XEnumerationAccess> mxObjEnumerationAccess;
+ Reference<XIdlArray> mxObjIdlArray;
+
+ Reference<XElementAccess> getXElementAccess();
+ Reference<XNameContainer> getXNameContainer();
+ Reference<XNameReplace> getXNameReplace();
+ Reference<XNameAccess> getXNameAccess();
+ Reference<XIndexContainer> getXIndexContainer();
+ Reference<XIndexReplace> getXIndexReplace();
+ Reference<XIndexAccess> getXIndexAccess();
+ Reference<XEnumerationAccess> getXEnumerationAccess();
+ Reference<XIdlArray> getXIdlArray();
+
+ void cacheXNameContainer();
+ void cacheXIndexContainer();
+
+public:
+ ImplIntrospectionAccess( const Any& obj, rtl::Reference< IntrospectionAccessStatic_Impl > const & pStaticImpl_ );
+
+ // Methods from XIntrospectionAccess
+ virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts() override;
+ virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts() override;
+ virtual Property SAL_CALL getProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
+ virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts) override;
+ virtual Reference<XIdlMethod> SAL_CALL getMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
+ virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts) override;
+ virtual Sequence< Type > SAL_CALL getSupportedListeners() override;
+ using OWeakObject::queryAdapter;
+ virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType ) override;
+
+ // Methods from XMaterialHolder
+ virtual Any SAL_CALL getMaterial() override;
+
+ // Methods from XExactName
+ virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override;
+
+ // Methods from XInterface
+ virtual Any SAL_CALL queryInterface( const Type& rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OWeakObject::release(); }
+
+ // Methods from XPropertySet
+ virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& aValue) override;
+ virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
+
+ // Methods from XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) override;
+ virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override;
+
+ // Methods from XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties() override;
+ virtual Property SAL_CALL getPropertyByName(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& Name) override;
+
+ // Methods from XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // Methods from XNameAccess
+ virtual Any SAL_CALL getByName(const OUString& Name) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;
+
+ // Methods from XNameReplace
+ virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element) override;
+
+ // Methods from XNameContainer
+ virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element) override;
+ virtual void SAL_CALL removeByName(const OUString& Name) override;
+
+ // Methods from XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual Any SAL_CALL getByIndex(sal_Int32 Index) override;
+
+ // Methods from XIndexReplace
+ virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element) override;
+
+ // Methods from XIndexContainer
+ virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) override;
+ virtual void SAL_CALL removeByIndex(sal_Int32 Index) override;
+
+ // Methods from XEnumerationAccess
+ virtual Reference<XEnumeration> SAL_CALL createEnumeration() override;
+
+ // Methods from XIdlArray
+ virtual void SAL_CALL realloc(Any& array, sal_Int32 length) override;
+ virtual sal_Int32 SAL_CALL getLen(const Any& array) override;
+ virtual Any SAL_CALL get(const Any& array, sal_Int32 index) override;
+ virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value) override;
+
+ // Methods from XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const Sequence< sal_Int8 >& aIdentifier ) override;
+};
+
+ImplIntrospectionAccess::ImplIntrospectionAccess
+ ( const Any& obj, rtl::Reference< IntrospectionAccessStatic_Impl > const & pStaticImpl_ )
+ : maInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ) ,
+ mnLastPropertyConcept(-1), mnLastMethodConcept(-1) //, maAdapter()
+{
+ // Save object as an interface if possible
+ maInspectedObject >>= mxIface;
+}
+
+Reference<XElementAccess> ImplIntrospectionAccess::getXElementAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjElementAccess.is() )
+ {
+ aGuard.unlock();
+ Reference<XElementAccess> xElementAccess( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjElementAccess.is() )
+ mxObjElementAccess = xElementAccess;
+ }
+ return mxObjElementAccess;
+}
+
+void ImplIntrospectionAccess::cacheXNameContainer()
+{
+ Reference<XNameContainer> xNameContainer;
+ Reference<XNameReplace> xNameReplace;
+ Reference<XNameAccess> xNameAccess;
+ if (mpStaticImpl->mbNameContainer)
+ {
+ xNameContainer.set( mxIface, UNO_QUERY );
+ xNameReplace = xNameContainer;
+ xNameAccess = xNameContainer;
+ }
+ else if (mpStaticImpl->mbNameReplace)
+ {
+ xNameReplace.set( mxIface, UNO_QUERY );
+ xNameAccess = xNameReplace;
+ }
+ else if (mpStaticImpl->mbNameAccess)
+ {
+ xNameAccess.set( mxIface, UNO_QUERY );
+ }
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if( !mxObjNameContainer.is() )
+ mxObjNameContainer = xNameContainer;
+ if( !mxObjNameReplace.is() )
+ mxObjNameReplace = xNameReplace;
+ if( !mxObjNameAccess.is() )
+ mxObjNameAccess = xNameAccess;
+ }
+}
+
+Reference<XNameContainer> ImplIntrospectionAccess::getXNameContainer()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameContainer.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameContainer;
+}
+
+Reference<XNameReplace> ImplIntrospectionAccess::getXNameReplace()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameReplace.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameReplace;
+}
+
+Reference<XNameAccess> ImplIntrospectionAccess::getXNameAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameAccess.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameAccess;
+}
+
+void ImplIntrospectionAccess::cacheXIndexContainer()
+{
+ Reference<XIndexContainer> xIndexContainer;
+ Reference<XIndexReplace> xIndexReplace;
+ Reference<XIndexAccess> xIndexAccess;
+ if (mpStaticImpl->mbIndexContainer)
+ {
+ xIndexContainer.set( mxIface, UNO_QUERY );
+ xIndexReplace = xIndexContainer;
+ xIndexAccess = xIndexContainer;
+ }
+ else if (mpStaticImpl->mbIndexReplace)
+ {
+ xIndexReplace.set( mxIface, UNO_QUERY );
+ xIndexAccess = xIndexReplace;
+ }
+ else if (mpStaticImpl->mbIndexAccess)
+ {
+ xIndexAccess.set( mxIface, UNO_QUERY );
+ }
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if( !mxObjIndexContainer.is() )
+ mxObjIndexContainer = xIndexContainer;
+ if( !mxObjIndexReplace.is() )
+ mxObjIndexReplace = xIndexReplace;
+ if( !mxObjIndexAccess.is() )
+ mxObjIndexAccess = xIndexAccess;
+ }
+}
+
+Reference<XIndexContainer> ImplIntrospectionAccess::getXIndexContainer()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexContainer.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexContainer;
+}
+
+Reference<XIndexReplace> ImplIntrospectionAccess::getXIndexReplace()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexReplace.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexReplace;
+}
+
+Reference<XIndexAccess> ImplIntrospectionAccess::getXIndexAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexAccess.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexAccess;
+}
+
+Reference<XEnumerationAccess> ImplIntrospectionAccess::getXEnumerationAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjEnumerationAccess.is() )
+ {
+ aGuard.unlock();
+ Reference<XEnumerationAccess> xEnumerationAccess( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjEnumerationAccess.is() )
+ mxObjEnumerationAccess = xEnumerationAccess;
+ }
+ return mxObjEnumerationAccess;
+}
+
+Reference<XIdlArray> ImplIntrospectionAccess::getXIdlArray()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIdlArray.is() )
+ {
+ aGuard.unlock();
+ Reference<XIdlArray> xIdlArray( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjIdlArray.is() )
+ mxObjIdlArray = xIdlArray;
+ }
+ return mxObjIdlArray;
+}
+
+// Methods from XInterface
+Any SAL_CALL ImplIntrospectionAccess::queryInterface( const Type& rType )
+{
+ Any aRet( ::cppu::queryInterface(
+ rType,
+ static_cast< XIntrospectionAccess * >( this ),
+ static_cast< XMaterialHolder * >( this ),
+ static_cast< XExactName * >( this ),
+ static_cast< XPropertySet * >( this ),
+ static_cast< XFastPropertySet * >( this ),
+ static_cast< XPropertySetInfo * >( this ) ) );
+ if( !aRet.hasValue() )
+ aRet = OWeakObject::queryInterface( rType );
+
+ if( !aRet.hasValue() )
+ {
+ // Wrapper for the object interfaces
+ ( mpStaticImpl->mbElementAccess && (aRet = ::cppu::queryInterface
+ ( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XNameReplace* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexReplace* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbEnumerationAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIdlArray && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbUnoTunnel && (aRet = ::cppu::queryInterface( rType, static_cast< XUnoTunnel* >( this ) ) ).hasValue() );
+ }
+ return aRet;
+}
+
+
+//*** Implementation of ImplIntrospectionAdapter ***
+
+
+// Methods from XPropertySet
+Reference<XPropertySetInfo> ImplIntrospectionAccess::getPropertySetInfo()
+{
+ return static_cast<XPropertySetInfo *>(this);
+}
+
+void ImplIntrospectionAccess::setPropertyValue(const OUString& aPropertyName, const Any& aValue)
+{
+ mpStaticImpl->setPropertyValue( maInspectedObject, aPropertyName, aValue );
+}
+
+Any ImplIntrospectionAccess::getPropertyValue(const OUString& aPropertyName)
+{
+ return mpStaticImpl->getPropertyValue( maInspectedObject, aPropertyName );
+}
+
+void ImplIntrospectionAccess::addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->addPropertyChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->removePropertyChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->addVetoableChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ if( xPropSet.is() )
+ xPropSet->removeVetoableChangeListener(aPropertyName, aListener);
+ }
+}
+
+
+// Methods from XFastPropertySet
+void ImplIntrospectionAccess::setFastPropertyValue(sal_Int32, const Any&)
+{
+}
+
+Any ImplIntrospectionAccess::getFastPropertyValue(sal_Int32)
+{
+ return Any();
+}
+
+// Methods from XPropertySetInfo
+Sequence< Property > ImplIntrospectionAccess::getProperties()
+{
+ return comphelper::containerToSequence(mpStaticImpl->getProperties());
+}
+
+Property ImplIntrospectionAccess::getPropertyByName(const OUString& Name)
+{
+ return getProperty( Name, PropertyConcept::ALL );
+}
+
+sal_Bool ImplIntrospectionAccess::hasPropertyByName(const OUString& Name)
+{
+ return hasProperty( Name, PropertyConcept::ALL );
+}
+
+// Methods from XElementAccess
+Type ImplIntrospectionAccess::getElementType()
+{
+ return getXElementAccess()->getElementType();
+}
+
+sal_Bool ImplIntrospectionAccess::hasElements()
+{
+ return getXElementAccess()->hasElements();
+}
+
+// Methods from XNameAccess
+Any ImplIntrospectionAccess::getByName(const OUString& Name)
+{
+ return getXNameAccess()->getByName( Name );
+}
+
+Sequence< OUString > ImplIntrospectionAccess::getElementNames()
+{
+ return getXNameAccess()->getElementNames();
+}
+
+sal_Bool ImplIntrospectionAccess::hasByName(const OUString& Name)
+{
+ return getXNameAccess()->hasByName( Name );
+}
+
+// Methods from XNameContainer
+void ImplIntrospectionAccess::insertByName(const OUString& Name, const Any& Element)
+{
+ getXNameContainer()->insertByName( Name, Element );
+}
+
+void ImplIntrospectionAccess::replaceByName(const OUString& Name, const Any& Element)
+{
+ getXNameReplace()->replaceByName( Name, Element );
+}
+
+void ImplIntrospectionAccess::removeByName(const OUString& Name)
+{
+ getXNameContainer()->removeByName( Name );
+}
+
+// Methods from XIndexAccess
+// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const
+sal_Int32 ImplIntrospectionAccess::getCount()
+{
+ return getXIndexAccess()->getCount();
+}
+
+Any ImplIntrospectionAccess::getByIndex(sal_Int32 Index)
+{
+ return getXIndexAccess()->getByIndex( Index );
+}
+
+// Methods from XIndexContainer
+void ImplIntrospectionAccess::insertByIndex(sal_Int32 Index, const Any& Element)
+{
+ getXIndexContainer()->insertByIndex( Index, Element );
+}
+
+void ImplIntrospectionAccess::replaceByIndex(sal_Int32 Index, const Any& Element)
+{
+ getXIndexReplace()->replaceByIndex( Index, Element );
+}
+
+void ImplIntrospectionAccess::removeByIndex(sal_Int32 Index)
+{
+ getXIndexContainer()->removeByIndex( Index );
+}
+
+// Methods from XEnumerationAccess
+// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const;
+Reference<XEnumeration> ImplIntrospectionAccess::createEnumeration()
+{
+ return getXEnumerationAccess()->createEnumeration();
+}
+
+// Methods from XIdlArray
+void ImplIntrospectionAccess::realloc(Any& array, sal_Int32 length)
+{
+ getXIdlArray()->realloc( array, length );
+}
+
+sal_Int32 ImplIntrospectionAccess::getLen(const Any& array)
+{
+ return getXIdlArray()->getLen( array );
+}
+
+Any ImplIntrospectionAccess::get(const Any& array, sal_Int32 index)
+{
+ return getXIdlArray()->get( array, index );
+}
+
+void ImplIntrospectionAccess::set(Any& array, sal_Int32 index, const Any& value)
+{
+ getXIdlArray()->set( array, index, value );
+}
+
+// Methods from XUnoTunnel
+sal_Int64 ImplIntrospectionAccess::getSomething( const Sequence< sal_Int8 >& aIdentifier )
+{
+ if (Reference<XUnoTunnel> xUnoTunnel{ mxIface, css::uno::UNO_QUERY })
+ return xUnoTunnel->getSomething(aIdentifier);
+ return 0;
+}
+
+
+//*** Implementation of ImplIntrospectionAccess ***
+
+// Methods from XIntrospectionAccess
+sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts()
+{
+ return MethodConcept::DANGEROUS |
+ PROPERTY |
+ LISTENER |
+ ENUMERATION |
+ NAMECONTAINER |
+ INDEXCONTAINER;
+}
+
+sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts()
+{
+ return PropertyConcept::DANGEROUS |
+ PROPERTYSET |
+ ATTRIBUTES |
+ METHODS;
+}
+
+Property ImplIntrospectionAccess::getProperty(const OUString& Name, sal_Int32 PropertyConcepts)
+{
+ Property aRet;
+ sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
+ bool bFound = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
+ if( (PropertyConcepts & nConcept) != 0 )
+ {
+ aRet = mpStaticImpl->getProperties()[ i ];
+ bFound = true;
+ }
+ }
+ if( !bFound )
+ throw NoSuchElementException(Name);
+ return aRet;
+}
+
+sal_Bool ImplIntrospectionAccess::hasProperty(const OUString& Name, sal_Int32 PropertyConcepts)
+{
+ sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
+ bool bRet = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
+ if( (PropertyConcepts & nConcept) != 0 )
+ bRet = true;
+ }
+ return bRet;
+}
+
+Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts)
+{
+ // If all supported concepts are required, simply pass through the sequence
+ sal_Int32 nAllSupportedMask = PROPERTYSET |
+ ATTRIBUTES |
+ METHODS;
+ if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask )
+ {
+ return comphelper::containerToSequence(mpStaticImpl->getProperties());
+ }
+
+ // Same sequence as last time?
+ if( mnLastPropertyConcept == PropertyConcepts )
+ {
+ return maLastPropertySeq;
+ }
+
+ // Number of properties to be delivered
+ sal_Int32 nCount = 0;
+
+ // There are currently no DANGEROUS properties
+ // if( PropertyConcepts & DANGEROUS )
+ // nCount += mpStaticImpl->mnDangerousPropCount;
+ if( PropertyConcepts & PROPERTYSET )
+ nCount += mpStaticImpl->mnPropertySetPropCount;
+ if( PropertyConcepts & ATTRIBUTES )
+ nCount += mpStaticImpl->mnAttributePropCount;
+ if( PropertyConcepts & METHODS )
+ nCount += mpStaticImpl->mnMethodPropCount;
+
+ // Realloc sequence according to the required number
+ maLastPropertySeq.realloc( nCount );
+ Property* pDestProps = maLastPropertySeq.getArray();
+
+ // Go through all the properties and apply according to the concept
+ const std::vector<Property>& rPropSeq = mpStaticImpl->getProperties();
+ const std::vector<sal_Int32>& rConcepts = mpStaticImpl->getPropertyConcepts();
+ sal_Int32 nLen = static_cast<sal_Int32>(rPropSeq.size());
+
+ sal_Int32 iDest = 0;
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Int32 nConcept = rConcepts[ i ];
+ if( nConcept & PropertyConcepts )
+ pDestProps[ iDest++ ] = rPropSeq[ i ];
+ }
+
+ // Remember PropertyConcept representing maLastPropertySeq
+ mnLastPropertyConcept = PropertyConcepts;
+
+ // Supply assembled Sequence
+ return maLastPropertySeq;
+}
+
+Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const OUString& Name, sal_Int32 MethodConcepts)
+{
+ Reference<XIdlMethod> xRet;
+ sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
+ if( i != -1 )
+ {
+
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( (MethodConcepts & nConcept) != 0 )
+ {
+ xRet = mpStaticImpl->getMethods()[i];
+ }
+ }
+ if( !xRet.is() )
+ throw NoSuchMethodException(Name);
+ return xRet;
+}
+
+sal_Bool ImplIntrospectionAccess::hasMethod(const OUString& Name, sal_Int32 MethodConcepts)
+{
+ sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
+ bool bRet = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( (MethodConcepts & nConcept) != 0 )
+ bRet = true;
+ }
+ return bRet;
+}
+
+Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts)
+{
+ // If all supported concepts are required, simply pass through the sequence
+ sal_Int32 nAllSupportedMask = MethodConcept::DANGEROUS |
+ PROPERTY |
+ LISTENER |
+ ENUMERATION |
+ NAMECONTAINER |
+ INDEXCONTAINER |
+ MethodConcept_NORMAL_IMPL;
+ if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask )
+ {
+ return comphelper::containerToSequence(mpStaticImpl->getMethods());
+ }
+
+ // Same sequence as last time?
+ if( mnLastMethodConcept == MethodConcepts )
+ {
+ return maLastMethodSeq;
+ }
+
+ // Get method sequences
+ const std::vector< Reference<XIdlMethod> >& aMethodSeq = mpStaticImpl->getMethods();
+ sal_Int32 nLen = static_cast<sal_Int32>(aMethodSeq.size());
+
+ // Realloc sequence according to the required number
+ // Unlike Properties, the number can not be determined by counters in
+ // inspect() beforehand, since methods can belong to several concepts
+ maLastMethodSeq.realloc( nLen );
+ Reference<XIdlMethod>* pDestMethods = maLastMethodSeq.getArray();
+
+ // Go through all the methods and apply according to the concept
+ sal_Int32 iDest = 0;
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( nConcept & MethodConcepts )
+ pDestMethods[ iDest++ ] = aMethodSeq[ i ];
+ }
+
+ // Bring to the correct length
+ maLastMethodSeq.realloc( iDest );
+
+ // Remember MethodConcept representing maLastMethodSeq
+ mnLastMethodConcept = MethodConcepts;
+
+ // Supply assembled Sequence
+ return maLastMethodSeq;
+}
+
+Sequence< Type > ImplIntrospectionAccess::getSupportedListeners()
+{
+ return comphelper::containerToSequence(mpStaticImpl->getSupportedListeners());
+}
+
+Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType )
+{
+ Reference<XInterface> xRet;
+ if( rType == cppu::UnoType<XInterface>::get()
+ || rType == cppu::UnoType<XPropertySet>::get()
+ || rType == cppu::UnoType<XFastPropertySet>::get()
+ || rType == cppu::UnoType<XPropertySetInfo>::get()
+ || rType == cppu::UnoType<XElementAccess>::get()
+ || rType == cppu::UnoType<XNameAccess>::get()
+ || rType == cppu::UnoType<XNameReplace>::get()
+ || rType == cppu::UnoType<XNameContainer>::get()
+ || rType == cppu::UnoType<XIndexAccess>::get()
+ || rType == cppu::UnoType<XIndexReplace>::get()
+ || rType == cppu::UnoType<XIndexContainer>::get()
+ || rType == cppu::UnoType<XEnumerationAccess>::get()
+ || rType == cppu::UnoType<XIdlArray>::get()
+ || rType == cppu::UnoType<XUnoTunnel>::get() )
+ {
+ queryInterface( rType ) >>= xRet;
+ }
+ return xRet;
+}
+
+// Methods from XMaterialHolder
+Any ImplIntrospectionAccess::getMaterial()
+{
+ return maInspectedObject;
+}
+
+// Methods from XExactName
+OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName )
+{
+ OUString aRetStr;
+ LowerToExactNameMap::iterator aIt =
+ mpStaticImpl->maLowerToExactNameMap.find( rApproximateName.toAsciiLowerCase() );
+ if (aIt != mpStaticImpl->maLowerToExactNameMap.end())
+ aRetStr = (*aIt).second;
+ return aRetStr;
+}
+
+struct TypeKey {
+ TypeKey(
+ css::uno::Reference<css::beans::XPropertySetInfo> const & theProperties,
+ std::vector<css::uno::Type> const & theTypes):
+ properties(theProperties)
+ {
+ //TODO: Could even sort the types lexicographically first, to increase
+ // the chance of matches between different implementations' getTypes(),
+ // but the old scheme of using getImplementationId() would have missed
+ // those matches, too:
+ OUStringBuffer b(static_cast<int>(theTypes.size() * 64));
+ for (const css::uno::Type& rType : theTypes) {
+ b.append(rType.getTypeName());
+ b.append('*'); // arbitrary delimiter not used by type grammar
+ }
+ types = b.makeStringAndClear();
+ }
+
+ css::uno::Reference<css::beans::XPropertySetInfo> properties;
+ OUString types;
+};
+
+struct TypeKeyLess {
+ bool operator ()(TypeKey const & key1, TypeKey const & key2) const {
+ if (key1.properties.get() < key2.properties.get()) {
+ return true;
+ }
+ if (key1.properties.get() > key2.properties.get()) {
+ return false;
+ }
+ return key1.types < key2.types;
+ }
+};
+
+template<typename Key, typename Less> class Cache {
+public:
+ rtl::Reference<IntrospectionAccessStatic_Impl> find(Key const & key) const {
+ typename Map::const_iterator i(map_.find(key));
+ if (i == map_.end()) {
+ return rtl::Reference<IntrospectionAccessStatic_Impl>();
+ } else {
+ if (i->second.hits < std::numeric_limits<unsigned>::max()) {
+ ++i->second.hits;
+ }
+ assert(i->second.access.is());
+ return i->second.access;
+ }
+ }
+
+ void insert(
+ Key const & key,
+ rtl::Reference<IntrospectionAccessStatic_Impl> const & access)
+ {
+ assert(access.is());
+ typename Map::size_type const MAX = 100;
+ assert(map_.size() <= MAX);
+ if (map_.size() == MAX) {
+ typename Map::iterator del = std::min_element(map_.begin(), map_.end(),
+ [](const typename Map::value_type& a, const typename Map::value_type& b) {
+ return a.second.hits < b.second.hits;
+ });
+ map_.erase(del);
+ }
+ bool ins = map_.emplace(key, Data(access)).second;
+ assert(ins); (void)ins;
+ }
+
+ void clear() { map_.clear(); }
+
+private:
+ struct Data {
+ explicit Data(
+ rtl::Reference<IntrospectionAccessStatic_Impl> const & theAccess):
+ access(theAccess), hits(1)
+ {}
+
+ rtl::Reference<IntrospectionAccessStatic_Impl> access;
+ mutable unsigned hits;
+ };
+
+ typedef std::map<Key, Data, Less> Map;
+
+ Map map_;
+};
+
+typedef
+ cppu::WeakComponentImplHelper<
+ css::lang::XServiceInfo, css::beans::XIntrospection>
+ Implementation_Base;
+
+class Implementation: private cppu::BaseMutex, public Implementation_Base {
+public:
+ explicit Implementation(
+ css::uno::Reference<css::uno::XComponentContext> const & context):
+ Implementation_Base(m_aMutex),
+ reflection_(css::reflection::theCoreReflection::get(context))
+ {}
+
+private:
+ virtual void SAL_CALL disposing() override {
+ osl::MutexGuard g(m_aMutex);
+ reflection_.clear();
+ typeCache_.clear();
+ }
+
+ virtual OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.Introspection"; }
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ virtual css::uno::Sequence<OUString> SAL_CALL
+ getSupportedServiceNames() override
+ {
+ Sequence<OUString> s { "com.sun.star.beans.Introspection" };
+ return s;
+ }
+
+ virtual css::uno::Reference<css::beans::XIntrospectionAccess> SAL_CALL
+ inspect(css::uno::Any const & aObject) override;
+
+ css::uno::Reference<css::reflection::XIdlReflection> reflection_;
+ Cache<TypeKey, TypeKeyLess> typeCache_;
+};
+
+css::uno::Reference<css::beans::XIntrospectionAccess> Implementation::inspect(
+ css::uno::Any const & aObject)
+{
+ css::uno::Reference<css::reflection::XIdlReflection> reflection;
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed || rBHelper.bInDispose) {
+ throw css::lang::DisposedException(
+ getImplementationName(), static_cast<OWeakObject *>(this));
+ }
+ reflection = reflection_;
+ }
+ css::uno::Any aToInspectObj;
+ css::uno::Type t;
+ if (aObject >>= t) {
+ css::uno::Reference<css::reflection::XIdlClass> c(
+ reflection->forName(t.getTypeName()));
+ if (!c.is()) {
+ SAL_WARN("stoc", "cannot reflect type " << t.getTypeName());
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+ }
+ aToInspectObj <<= c;
+ } else {
+ aToInspectObj = aObject;
+ }
+
+ // Examine object
+ TypeClass eType = aToInspectObj.getValueType().getTypeClass();
+ if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT && eType != TypeClass_EXCEPTION )
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+
+ if( auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj) )
+ {
+ if( !x->is() )
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+ }
+
+ // Pointer to possibly needed new IntrospectionAccessStatic_Impl instance
+ rtl::Reference< IntrospectionAccessStatic_Impl > pAccess;
+
+ // Check: Is a matching access object already cached?
+ std::vector< Reference<XIdlClass> > SupportedClassSeq;
+ std::vector< Type > SupportedTypesSeq;
+ Reference<XTypeProvider> xTypeProvider;
+ Reference<XPropertySetInfo> xPropSetInfo;
+ Reference<XPropertySet> xPropSet;
+
+ // Look for interfaces XTypeProvider and PropertySet
+ if( eType == TypeClass_INTERFACE )
+ {
+ xTypeProvider.set( aToInspectObj, UNO_QUERY );
+ if( xTypeProvider.is() )
+ {
+ SupportedTypesSeq = comphelper::sequenceToContainer<std::vector<Type>>(xTypeProvider->getTypes());
+ } else {
+ SAL_WARN(
+ "stoc",
+ "object of type \"" << aToInspectObj.getValueTypeName()
+ << "\" lacks XTypeProvider");
+ SupportedTypesSeq = { aToInspectObj.getValueType() };
+ }
+ // Now try to get the PropertySetInfo
+ xPropSet.set( aToInspectObj, UNO_QUERY );
+ if( xPropSet.is() )
+ xPropSetInfo = xPropSet->getPropertySetInfo();
+
+ } else {
+ SupportedTypesSeq = { aToInspectObj.getValueType() };
+ }
+
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed || rBHelper.bInDispose) {
+ throw css::lang::DisposedException(
+ getImplementationName(), static_cast<OWeakObject *>(this));
+ }
+ TypeKey key(xPropSetInfo, SupportedTypesSeq);
+ pAccess = typeCache_.find(key);
+ if (pAccess.is()) {
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+ }
+ pAccess = new IntrospectionAccessStatic_Impl(reflection);
+ typeCache_.insert(key, pAccess);
+ }
+
+ // No access cached -> create new
+ std::vector<Property>& rAllPropArray = pAccess->maAllPropertySeq;
+ std::vector<Reference<XInterface>>& rInterfaces1 = pAccess->aInterfaceSeq1;
+ std::vector<Reference<XInterface>>& rInterfaces2 = pAccess->aInterfaceSeq2;
+ std::vector<sal_Int16>& rMapTypeArray = pAccess->maMapTypeSeq;
+ std::vector<sal_Int32>& rPropertyConceptArray = pAccess->maPropertyConceptSeq;
+
+ // References to important data from pAccess
+ sal_Int32& rPropCount = pAccess->mnPropCount;
+ IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap;
+ IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap;
+ LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap;
+
+
+ //*** Perform analysis ***
+
+ if( eType == TypeClass_INTERFACE )
+ {
+ size_t nTypeCount = SupportedTypesSeq.size();
+ if( nTypeCount )
+ {
+ SupportedClassSeq.resize( nTypeCount );
+
+ for( size_t i = 0 ; i < nTypeCount ; i++ )
+ SupportedClassSeq[i] = reflection->forName( SupportedTypesSeq[i].getTypeName() );
+ }
+
+ // First look for particular interfaces that are of particular
+ // importance to the introspection
+
+ // Is XPropertySet present?
+ if( xPropSet.is() && xPropSetInfo.is() )
+ {
+ // Is there also a FastPropertySet?
+ Reference<XFastPropertySet> xDummy( aToInspectObj, UNO_QUERY );
+ bool bFast = pAccess->mbFastPropSet = xDummy.is();
+
+ Sequence<Property> aPropSeq = xPropSetInfo->getProperties();
+ const Property* pProps = aPropSeq.getConstArray();
+ sal_Int32 nLen = aPropSeq.getLength();
+
+ // For a FastPropertySet we must remember the original handles
+ if( bFast )
+ pAccess->mpOrgPropertyHandleArray.reset( new sal_Int32[ nLen ] );
+
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ // Put property in its own list
+ pAccess->checkPropertyArraysSize( rPropCount );
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp = pProps[ i ];
+
+ if( bFast )
+ pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;
+
+ // Enter PropCount as a handle for its own FastPropertySet
+ rProp.Handle = rPropCount;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
+ rPropertyConceptArray[ rPropCount ] = PROPERTYSET;
+ pAccess->mnPropertySetPropCount++;
+
+ // Enter name in hash table if not already known
+ OUString aPropName = rProp.Name;
+
+ // Do we already have the name?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if( aIt == rPropNameMap.end() )
+ {
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+ }
+ else
+ {
+ SAL_WARN( "stoc", "Introspection: Property \"" <<
+ aPropName << "\" found more than once in PropertySet" );
+ }
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+ // Indices in the export table
+ sal_Int32 iAllExportedMethod = 0;
+ sal_Int32 iAllSupportedListener = 0;
+
+ std::set<OUString> seen;
+
+ // Flag, whether XInterface methods should be recorded
+ // (this must be done only once, allowed initially)
+ bool bXInterfaceIsInvalid = false;
+
+ // Flag whether the XInterface methods have already been recorded. If
+ // sal_True, bXInterfaceIsInvalid is activated at the end of the interface
+ // loop, and XInterface methods are cut off thereafter.
+ bool bFoundXInterface = false;
+
+ size_t nClassCount = SupportedClassSeq.size();
+ for( size_t nIdx = 0 ; nIdx < nClassCount; nIdx++ )
+ {
+ Reference<XIdlClass> xImplClass2 = SupportedClassSeq[nIdx];
+ while( xImplClass2.is() )
+ {
+ // Fetch interfaces from the implementation
+ Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces();
+ sal_Int32 nIfaceCount = aClassSeq.getLength();
+
+ aClassSeq.realloc( nIfaceCount + 1 );
+ aClassSeq.getArray()[ nIfaceCount ] = xImplClass2;
+
+ for( const Reference<XIdlClass>& rxIfaceClass : std::as_const(aClassSeq) )
+ {
+ if (!seen.insert(rxIfaceClass->getName()).second) {
+ continue;
+ }
+
+ // 2. Register fields as properties
+
+ // Get fields
+ const Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields();
+
+ for( const Reference<XIdlField>& xField : fields )
+ {
+ Reference<XIdlClass> xPropType = xField->getType();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Enter in own property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ OUString aFieldName = xField->getName();
+ rProp.Name = aFieldName;
+ rProp.Handle = rPropCount;
+ Type aFieldType( xPropType->getTypeClass(), xPropType->getName() );
+ rProp.Type = aFieldType;
+ FieldAccessMode eAccessMode = xField->getAccessMode();
+ rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
+ eAccessMode == FieldAccessMode_CONST)
+ ? READONLY : 0;
+
+ // Enter name in hash table
+ OUString aPropName = rProp.Name;
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ continue;
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember field
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = xField;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_FIELD;
+ rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
+ pAccess->mnAttributePropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+
+
+ // 3. Methods
+
+ // Get and remember all methods
+ Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods();
+ const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
+ sal_Int32 nSourceMethodCount = methods.getLength();
+
+ // 3. a) Search get/set and listener methods
+
+ // Create field for information about the methods, so that methods which are not
+ // related to properties or listeners can easily be found later.
+ // New: initialise MethodConceptArray
+ enum MethodType
+ {
+ STANDARD_METHOD, // normal method, not related to properties or listeners
+ GETSET_METHOD, // belongs to a get/set property
+ ADD_LISTENER_METHOD, // add method of a listener interface
+ REMOVE_LISTENER_METHOD, // remove method of a listener interface
+ INVALID_METHOD // method whose class is not considered, e.g. XPropertySet
+ };
+ std::unique_ptr<MethodType[]> pMethodTypes( new MethodType[ nSourceMethodCount ] );
+ std::unique_ptr<sal_Int32[]> pLocalMethodConcepts( new sal_Int32[ nSourceMethodCount ] );
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ pMethodTypes[ i ] = STANDARD_METHOD;
+ pLocalMethodConcepts[ i ] = 0;
+ }
+
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
+ sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
+
+ // Fetch name
+ OUString aMethName = rxMethod_i->getName();
+
+ // Catalogue methods
+ // Filter all (?) methods of XInterface so e.g. acquire and release
+ // can not be called from scripting
+ OUString className(
+ rxMethod_i->getDeclaringClass()->getName());
+ if (className == "com.sun.star.uno.XInterface") {
+ bFoundXInterface = true;
+
+ if( bXInterfaceIsInvalid )
+ {
+ pMethodTypes[ i ] = INVALID_METHOD;
+ continue;
+ }
+ else
+ {
+ if( aMethName != "queryInterface" )
+ {
+ rMethodConcept_i |= MethodConcept::DANGEROUS;
+ continue;
+ }
+ }
+ } else if (className == "com.sun.star.uno.XAggregation")
+ {
+ if( aMethName == "setDelegator" )
+ {
+ rMethodConcept_i |= MethodConcept::DANGEROUS;
+ continue;
+ }
+ } else if (className
+ == "com.sun.star.container.XElementAccess")
+ {
+ rMethodConcept_i |= ( NAMECONTAINER |
+ INDEXCONTAINER |
+ ENUMERATION );
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameContainer")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameContainer = true;
+ pAccess->mbNameReplace = true;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameReplace")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameReplace = true;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameAccess")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexContainer")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexContainer = true;
+ pAccess->mbIndexReplace = true;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexReplace")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexReplace = true;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexAccess")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XEnumerationAccess")
+ {
+ rMethodConcept_i |= ENUMERATION;
+ pAccess->mbEnumerationAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.reflection.XIdlArray")
+ {
+ pAccess->mbIdlArray = true;
+ } else if (className
+ == "com.sun.star.lang.XUnoTunnel")
+ {
+ pAccess->mbUnoTunnel = true;
+ }
+
+ // If the name is too short, it isn't anything
+ if( aMethName.getLength() <= 3 )
+ continue;
+
+ // Is it a get method?
+ OUString aPropName;
+ if( aMethName.startsWith("get", &aPropName) )
+ {
+ // Get methods must not have any parameters
+ Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes();
+ if( getParams.hasElements() )
+ {
+ continue;
+ }
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ {
+ /* TODO
+ SAL_INFO("stoc",(
+ String( "Introspection: Property \"" ) +
+ OOUStringToString( aPropName, CHARSET_SYSTEM ) +
+ String( "\" found more than once" ) );
+ */
+ continue;
+ }
+
+ // It is already at least a read-only property
+ rMethodConcept_i |= PROPERTY;
+
+ pMethodTypes[i] = GETSET_METHOD;
+ Reference<XIdlClass> xGetRetType = rxMethod_i->getReturnType();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
+ rProp.Attributes = READONLY;
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember get method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = rxMethod_i;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_GETSET;
+ rPropertyConceptArray[ rPropCount ] = METHODS;
+ pAccess->mnMethodPropCount++;
+
+ // Search for matching set method
+ sal_Int32 k;
+ for( k = 0 ; k < nSourceMethodCount ; k++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
+
+ // Accept only methods that are not already assigned
+ if( k == i || pMethodTypes[k] != STANDARD_METHOD )
+ continue;
+
+ // Get name and evaluate
+ OUString aMethName2 = rxMethod_k->getName();
+ OUString aPropName2;
+ if (!(aMethName2.startsWith("set", &aPropName2)
+ && aPropName2 == aPropName))
+ continue;
+
+ // A set method must return void
+ Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType();
+ if( xSetRetType->getTypeClass() != TypeClass_VOID )
+ {
+ continue;
+ }
+
+ // A set method may only have one parameter
+ Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes();
+ sal_Int32 nParamCount = setParams.getLength();
+ if( nParamCount != 1 )
+ {
+ continue;
+ }
+
+ // Next, the return type must correspond to the parameter type
+ const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray();
+ Reference<XIdlClass> xParamType = pParamArray2[ 0 ];
+ if( xParamType->equals( xGetRetType ) )
+ {
+ pLocalMethodConcepts[ k ] = PROPERTY;
+
+ pMethodTypes[k] = GETSET_METHOD;
+
+ // Delete read-only flag again
+ rProp.Attributes &= ~READONLY;
+
+ // Remember set method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
+ rInterfaces2, rPropCount );
+ rInterfaces2[ rPropCount ] = rxMethod_k;
+ }
+ }
+
+ // Adjust count
+ rPropCount++;
+ }
+
+ // Is it an add listener method?
+ else if( aMethName.startsWith("add", &aPropName) )
+ {
+ // Does it end with "Listener"?
+ OUString aListenerName;
+ if( !aPropName.endsWith("Listener", &aListenerName) )
+ continue;
+
+ // TODO: More accurate tests could still be carried out here
+ // - Return type
+ // - Number and type of parameters
+
+
+ // Search for matching remove method, otherwise not applicable
+ sal_Int32 k;
+ for( k = 0 ; k < nSourceMethodCount ; k++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
+
+ // Accept only methods that are not already assigned
+ if( k == i || pMethodTypes[k] != STANDARD_METHOD )
+ continue;
+
+ // Get name and evaluate
+ OUString aMethName2 = rxMethod_k->getName();
+ OUString aListenerName2;
+ if (!(aMethName2.startsWith(
+ "remove", &aPropName)
+ && aPropName.endsWith(
+ "Listener", &aListenerName2)
+ && aListenerName2 == aListenerName))
+ continue;
+
+ // TODO: More accurate tests could still be carried out here
+ // - Return type
+ // - Number and type of parameters
+
+
+ // Methods are recognised as a listener interface
+ rMethodConcept_i |= LISTENER;
+ pLocalMethodConcepts[ k ] |= LISTENER;
+
+ pMethodTypes[i] = ADD_LISTENER_METHOD;
+ pMethodTypes[k] = REMOVE_LISTENER_METHOD;
+ }
+ }
+ }
+
+
+ // A set method could still exist without a corresponding get method,
+ // this must be a write-only property
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
+
+ // Accept only methods that are not already assigned
+ if( pMethodTypes[i] != STANDARD_METHOD )
+ continue;
+
+ // Get name
+ OUString aMethName = rxMethod_i->getName();
+
+ // If the name is too short, it isn't anything
+ if( aMethName.getLength() <= 3 )
+ continue;
+
+ // Is it a set method without associated get method?
+ OUString aPropName;
+ if( aMethName.startsWith("set", &aPropName) )
+ {
+ // A set method must return void
+ Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType();
+ if( xSetRetType->getTypeClass() != TypeClass_VOID )
+ {
+ continue;
+ }
+
+ // A set method may only have one parameter
+ Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes();
+ sal_Int32 nParamCount = setParams.getLength();
+ if( nParamCount != 1 )
+ {
+ continue;
+ }
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ {
+ /* TODO:
+ SAL_INFO("stoc",(
+ String( "Introspection: Property \"" ) +
+ OOUStringToString( aPropName, CHARSET_SYSTEM ) +
+ String( "\" found more than once" ) );
+ */
+ continue;
+ }
+
+ // Now we know it's a write only property
+ pLocalMethodConcepts[ i ] = PROPERTY;
+
+ pMethodTypes[i] = GETSET_METHOD;
+ Reference<XIdlClass> xGetRetType = setParams.getConstArray()[0];
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
+ rProp.Attributes = 0; // PROPERTY_WRITEONLY ???
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember set method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
+ rInterfaces2, rPropCount );
+ rInterfaces2[ rPropCount ] = rxMethod_i;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_SETONLY;
+ rPropertyConceptArray[ rPropCount ] = METHODS;
+ pAccess->mnMethodPropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+
+ // 4. Place methods in overall sequence
+
+ // How many methods in the method sequence
+ sal_Int32 nExportedMethodCount = 0;
+ sal_Int32 nSupportedListenerCount = 0;
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ if( pMethodTypes[ i ] != INVALID_METHOD )
+ {
+ nExportedMethodCount++;
+ }
+ if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
+ {
+ nSupportedListenerCount++;
+ }
+ }
+
+ // Enlarge sequences in the access object accordingly
+ pAccess->maAllMethodSeq.resize( nExportedMethodCount + iAllExportedMethod );
+ pAccess->maMethodConceptSeq.resize( nExportedMethodCount + iAllExportedMethod );
+ pAccess->maSupportedListenerSeq.resize( nSupportedListenerCount + iAllSupportedListener );
+
+ // Write in methods
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ if( pMethodTypes[ i ] != INVALID_METHOD )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
+
+ // Enter name in hash table if not already known
+ OUString aMethName2 = rxMethod->getName();
+ IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 );
+ if( aIt == rMethodNameMap.end() )
+ {
+ // Enter
+ rMethodNameMap[ aMethName2 ] = iAllExportedMethod;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aMethName2.toAsciiLowerCase() ] = aMethName2;
+ }
+ else
+ {
+ sal_Int32 iHashResult = aIt->second;
+
+ Reference<XIdlMethod> xExistingMethod = pAccess->maAllMethodSeq[iHashResult];
+
+ Reference< XIdlClass > xExistingMethClass =
+ xExistingMethod->getDeclaringClass();
+ Reference< XIdlClass > xNewMethClass = rxMethod->getDeclaringClass();
+ if( xExistingMethClass->equals( xNewMethClass ) )
+ continue;
+ }
+
+ pAccess->maAllMethodSeq[iAllExportedMethod] = rxMethod;
+
+ // If a concept has been set, is the method "normal"?
+ sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
+ if( !rMethodConcept_i )
+ rMethodConcept_i = MethodConcept_NORMAL_IMPL;
+ pAccess->maMethodConceptSeq[ iAllExportedMethod ] = rMethodConcept_i;
+ iAllExportedMethod++;
+ }
+ if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
+ {
+ // Determine class of listener
+ const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
+
+ // Enter void as default class
+ css::uno::Reference<css::reflection::XIdlClass>
+ xListenerClass(
+ reflection->forName(
+ cppu::UnoType<void>::get()
+ .getTypeName()));
+ // Old: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass();
+
+ // Option 1: Search for parameters for a listener class
+ // Disadvantage: Superclasses should be searched recursively
+ const Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes();
+
+ css::uno::Reference<css::reflection::XIdlClass>
+ xEventListenerClass(
+ reflection->forName(
+ cppu::UnoType<
+ css::lang::XEventListener>::get()
+ .getTypeName()));
+ // Old: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass();
+ auto pParam = std::find_if(aParams.begin(), aParams.end(),
+ [&xEventListenerClass](const Reference<XIdlClass>& rxClass) {
+ // Are we derived from a listener?
+ return rxClass->equals( xEventListenerClass )
+ || isDerivedFrom( rxClass, xEventListenerClass );
+ });
+ if (pParam != aParams.end())
+ {
+ xListenerClass = *pParam;
+ }
+
+ // Option 2: Unload the name of the method
+ // Disadvantage: Does not work with test listeners, where it does not exist
+ //aMethName = rxMethod->getName();
+ //aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 );
+ //Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName );
+ Type aListenerType( TypeClass_INTERFACE, xListenerClass->getName() );
+ pAccess->maSupportedListenerSeq[ iAllSupportedListener ] = aListenerType;
+ iAllSupportedListener++;
+ }
+ }
+
+ // When there were XInterface methods in this run,
+ // ignore them in the future
+ if( bFoundXInterface )
+ bXInterfaceIsInvalid = true;
+ }
+
+ // Do superclasses exist? Then continue here
+ Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses();
+
+ // Currently only one superclass is considered
+ if( aSuperClassSeq.getLength() >= 1 )
+ {
+ xImplClass2 = aSuperClassSeq.getConstArray()[0];
+ OSL_ENSURE( xImplClass2.is(), "super class null" );
+ }
+ else
+ {
+ xImplClass2 = nullptr;
+ }
+ }
+ }
+
+ // Apply number of exported methods and adapt Sequences
+ // (can be different because duplicate methods are thrown
+ // out only after the determination of nExportedMethodCount)
+ sal_Int32& rMethCount = pAccess->mnMethCount;
+ rMethCount = iAllExportedMethod;
+ pAccess->maAllMethodSeq.resize( rMethCount );
+ pAccess->maMethodConceptSeq.resize( rMethCount );
+
+ // Resize the property sequences
+ pAccess->maAllPropertySeq.resize( rPropCount );
+ pAccess->maPropertyConceptSeq.resize( rPropCount );
+ pAccess->maMapTypeSeq.resize( rPropCount );
+ }
+ // Register struct fields as properties
+ else //if( eType == TypeClass_STRUCT )
+ {
+ // Is it an interface or a struct?
+ //Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass();
+ css::uno::Reference<css::reflection::XIdlClass> xClassRef(
+ reflection->forName(aToInspectObj.getValueTypeName()));
+ if( !xClassRef.is() )
+ {
+ SAL_WARN( "stoc", "Can't get XIdlClass from Reflection" );
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+ }
+
+ // Get fields
+ const Sequence< Reference<XIdlField> > fields = xClassRef->getFields();
+
+ for( const Reference<XIdlField>& xField : fields )
+ {
+ Reference<XIdlClass> xPropType = xField->getType();
+ OUString aPropName = xField->getName();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xPropType->getTypeClass(), xPropType->getName() );
+ FieldAccessMode eAccessMode = xField->getAccessMode();
+ rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
+ eAccessMode == FieldAccessMode_CONST)
+ ? READONLY : 0;
+
+ //FieldAccessMode eAccessMode = xField->getAccessMode();
+ //rProp.Attributes = (eAccessMode == FieldAccessMode::READONLY || eAccessMode == CONST)
+ //? PropertyAttribute::READONLY : 0;
+
+ // Write name in hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember field
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = xField;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_FIELD;
+ rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
+ pAccess->mnAttributePropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+ // Set property sequence to the correct length
+ pAccess->maAllPropertySeq.resize( pAccess->mnPropCount );
+
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_Introspection_get_implementation(
+ css::uno::XComponentContext * context,
+ css::uno::Sequence<css::uno::Any> const & arguments)
+{
+ SAL_WARN_IF(
+ arguments.hasElements(), "stoc", "unexpected singleton arguments");
+ return cppu::acquire(new Implementation(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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>
diff --git a/stoc/source/javaloader/javaloader.component b/stoc/source/javaloader/javaloader.component
new file mode 100644
index 000000000..e8d1533ba
--- /dev/null
+++ b/stoc/source/javaloader/javaloader.component
@@ -0,0 +1,28 @@
+<?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.JavaComponentLoader"
+ constructor="stoc_JavaComponentLoader_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.loader.Java"/>
+ <service name="com.sun.star.loader.Java2"/>
+ </implementation>
+</component>
diff --git a/stoc/source/javaloader/javaloader.cxx b/stoc/source/javaloader/javaloader.cxx
new file mode 100644
index 000000000..9b9195fbd
--- /dev/null
+++ b/stoc/source/javaloader/javaloader.cxx
@@ -0,0 +1,571 @@
+/* -*- 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 <rtl/process.h>
+#include <sal/log.hxx>
+
+#include <uno/environment.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+
+#ifdef LINUX
+#undef minor
+#undef major
+#endif
+
+#include <com/sun/star/java/XJavaVM.hpp>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <rtl/random.h>
+#include <rtl/ustrbuf.hxx>
+#include <osl/security.hxx>
+#include <osl/thread.hxx>
+
+#include <cppuhelper/factory.hxx>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/bridge/UnoUrlResolver.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/loader/XImplementationLoader.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/util/theMacroExpander.hpp>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+
+// this one is header-only
+#include <comphelper/sequence.hxx>
+
+namespace com::sun::star::registry { class XRegistryKey; }
+
+using namespace css::java;
+using namespace css::lang;
+using namespace css::loader;
+using namespace css::uno;
+using namespace css::registry;
+
+using namespace ::cppu;
+using namespace ::osl;
+
+namespace stoc_javaloader {
+
+namespace {
+
+// from desktop/source/deployment/misc/dp_misc.cxx
+OUString generateRandomPipeId()
+{
+ // compute some good pipe id:
+ static rtlRandomPool s_hPool = rtl_random_createPool();
+ if (s_hPool == nullptr)
+ throw RuntimeException( "cannot create random pool!?", nullptr );
+ sal_uInt8 bytes[ 32 ];
+ if (rtl_random_getBytes(
+ s_hPool, bytes, SAL_N_ELEMENTS(bytes) ) != rtl_Random_E_None) {
+ throw RuntimeException( "random pool error!?", nullptr );
+ }
+ OUStringBuffer buf;
+ for (unsigned char byte : bytes) {
+ buf.append( static_cast<sal_Int32>(byte), 0x10 );
+ }
+ return buf.makeStringAndClear();
+}
+
+// from desktop/source/deployment/registry/component/dp_component.cxx
+/** return a vector of bootstrap variables which have been provided
+ as command arguments.
+*/
+std::vector<OUString> getCmdBootstrapVariables()
+{
+ std::vector<OUString> ret;
+ sal_uInt32 count = osl_getCommandArgCount();
+ for (sal_uInt32 i = 0; i < count; i++)
+ {
+ OUString arg;
+ osl_getCommandArg(i, &arg.pData);
+ if (arg.startsWith("-env:"))
+ ret.push_back(arg);
+ }
+ return ret;
+}
+
+// from desktop/source/deployment/misc/dp_misc.cxx
+oslProcess raiseProcess(
+ OUString const & appURL, Sequence<OUString> const & args )
+{
+ ::osl::Security sec;
+ oslProcess hProcess = nullptr;
+ oslProcessError rc = osl_executeProcess(
+ appURL.pData,
+ reinterpret_cast<rtl_uString **>(
+ const_cast<OUString *>(args.getConstArray()) ),
+ args.getLength(),
+ osl_Process_DETACHED,
+ sec.getHandle(),
+ nullptr, // => current working dir
+ nullptr, 0, // => no env vars
+ &hProcess );
+
+ switch (rc) {
+ case osl_Process_E_None:
+ break;
+ case osl_Process_E_NotFound:
+ throw RuntimeException( "image not found!", nullptr );
+ case osl_Process_E_TimedOut:
+ throw RuntimeException( "timeout occurred!", nullptr );
+ case osl_Process_E_NoPermission:
+ throw RuntimeException( "permission denied!", nullptr );
+ case osl_Process_E_Unknown:
+ throw RuntimeException( "unknown error!", nullptr );
+ case osl_Process_E_InvalidError:
+ default:
+ throw RuntimeException( "unmapped error!", nullptr );
+ }
+
+ return hProcess;
+}
+
+// from desktop/source/deployment/registry/component/dp_component.cxx
+Reference<XComponentContext> raise_uno_process(
+ Reference<XComponentContext> const & xContext)
+{
+ OSL_ASSERT( xContext.is() );
+
+ OUString const url(css::util::theMacroExpander::get(xContext)->expandMacros("$URE_BIN_DIR/uno"));
+
+ const OUString connectStr = "uno:pipe,name=" + generateRandomPipeId() + ";urp;uno.ComponentContext";
+
+ // raise core UNO process to register/run a component,
+ // javavm service uses unorc next to executable to retrieve deployed
+ // jar typelibs
+
+ std::vector<OUString> args{
+#if OSL_DEBUG_LEVEL == 0
+ "--quiet",
+#endif
+ "--singleaccept",
+ "-u",
+ connectStr,
+ // don't inherit from unorc:
+ "-env:INIFILENAME=" };
+
+ //now add the bootstrap variables which were supplied on the command line
+ std::vector<OUString> bootvars = getCmdBootstrapVariables();
+ args.insert(args.end(), bootvars.begin(), bootvars.end());
+
+ oslProcess hProcess;
+ try {
+ hProcess = raiseProcess(url, comphelper::containerToSequence(args));
+ }
+ catch (...) {
+ OUStringBuffer sMsg = "error starting process: " + url;
+ for (const auto& arg : args) {
+ sMsg.append(" " + arg);
+ }
+ throw css::uno::RuntimeException(sMsg.makeStringAndClear());
+ }
+ try {
+ // from desktop/source/deployment/misc/dp_misc.cxx
+ Reference<css::bridge::XUnoUrlResolver> const xUnoUrlResolver(
+ css::bridge::UnoUrlResolver::create(xContext) );
+
+ for (int i = 0; i <= 40; ++i) // 20 seconds
+ {
+ try {
+ return Reference<XComponentContext>(
+ xUnoUrlResolver->resolve(connectStr),
+ UNO_QUERY_THROW );
+ }
+ catch (const css::connection::NoConnectException &) {
+ if (i < 40) {
+ ::osl::Thread::wait( std::chrono::milliseconds(500) );
+ }
+ else throw;
+ }
+ }
+ return nullptr; // warning C4715
+ }
+ catch (...) {
+ // try to terminate process:
+ if ( osl_terminateProcess( hProcess ) != osl_Process_E_None )
+ {
+ OSL_ASSERT( false );
+ }
+ throw;
+ }
+}
+
+class JavaComponentLoader
+ : protected ::cppu::BaseMutex
+ , public WeakComponentImplHelper<XImplementationLoader, XServiceInfo>
+{
+ /** local context */
+ css::uno::Reference<XComponentContext> m_xComponentContext;
+
+ /** possible remote process' context (use depends on configuration).
+ note: lifetime must be effectively "static" as this JavaComponentLoader
+ has no control over the lifetime of the services created via this
+ context; hence JavaComponentLoader is a single-instance service.
+ */
+ css::uno::Reference<XComponentContext> m_xRemoteComponentContext;
+
+ /** Do not use m_javaLoader directly. Instead use getJavaLoader.
+ This is either an in-process loader implemented in Java,
+ or a remote instance of JavaComponentLoader running in uno process,
+ acting as a proxy.
+ */
+ css::uno::Reference<XImplementationLoader> m_javaLoader;
+ /** The returned Reference contains a null pointer if the office is not configured
+ to run java.
+
+ @exception css::uno::RuntimeException
+ If the Java implementation of the loader could not be obtained, for reasons other
+ then that java was not configured the RuntimeException is thrown.
+ */
+ const css::uno::Reference<XImplementationLoader> & getJavaLoader(OUString &);
+
+
+public:
+ /// @throws RuntimeException
+ explicit JavaComponentLoader(const css::uno::Reference<XComponentContext> & xCtx);
+
+public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // XImplementationLoader
+ virtual css::uno::Reference<XInterface> SAL_CALL activate(
+ const OUString& implementationName, const OUString& implementationLoaderUrl,
+ const OUString& locationUrl, const css::uno::Reference<XRegistryKey>& xKey) override;
+ virtual sal_Bool SAL_CALL writeRegistryInfo(
+ const css::uno::Reference<XRegistryKey>& xKey,
+ const OUString& implementationLoaderUrl, const OUString& locationUrl) override;
+};
+
+}
+
+void JavaComponentLoader::disposing()
+{
+ // Explicitly drop all remote refs to shut down the uno.bin process
+ // and particularly the connection to it, so that it can't do more calls
+ // during late shutdown.
+ m_javaLoader.clear();
+ if (m_xRemoteComponentContext.is()) {
+ Reference<XComponent> const xComp(m_xRemoteComponentContext, UNO_QUERY);
+ assert(xComp.is());
+ xComp->dispose();
+ m_xRemoteComponentContext.clear();
+ }
+}
+
+const css::uno::Reference<XImplementationLoader> & JavaComponentLoader::getJavaLoader(OUString & rRemoteArg)
+{
+ static Mutex ourMutex;
+ MutexGuard aGuard(ourMutex);
+
+ if (m_javaLoader.is())
+ return m_javaLoader;
+
+ // check if the JVM should be instantiated out-of-process
+ if (rRemoteArg.isEmpty()) {
+ if (!m_xRemoteComponentContext.is()) {
+ Reference<css::container::XHierarchicalNameAccess> const xConf(
+ m_xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.configuration.ReadOnlyAccess",
+ { Any(OUString("*")) }, // locale isn't relevant here
+ m_xComponentContext),
+ UNO_QUERY);
+
+ // configmgr is not part of URE, so may not exist!
+ if (xConf.is()) {
+ Any const value(xConf->getByHierarchicalName(
+ "org.openoffice.Office.Java/VirtualMachine/RunUnoComponentsOutOfProcess"));
+ bool b;
+ if ((value >>= b) && b) {
+ SAL_INFO("stoc.java", "JavaComponentLoader: starting uno process");
+ m_xRemoteComponentContext = raise_uno_process(m_xComponentContext);
+ }
+ }
+ }
+ if (m_xRemoteComponentContext.is()) {
+ SAL_INFO("stoc.java", "JavaComponentLoader: creating remote instance to start JVM in uno process");
+ // create JVM service in remote uno.bin process
+ Reference<XImplementationLoader> const xLoader(
+ m_xRemoteComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.loader.Java2", m_xRemoteComponentContext),
+ UNO_QUERY_THROW);
+ assert(xLoader.is());
+ m_javaLoader = xLoader;
+ rRemoteArg = "remote";
+ SAL_INFO("stoc.java", "JavaComponentLoader: remote proxy instance created: " << m_javaLoader.get());
+ return m_javaLoader;
+ }
+ }
+
+ uno_Environment * pJava_environment = nullptr;
+ uno_Environment * pUno_environment = nullptr;
+ typelib_InterfaceTypeDescription * pType_XImplementationLoader = nullptr;
+
+ try {
+ // get a java vm, where we can create a loader
+ css::uno::Reference<XJavaVM> javaVM_xJavaVM(
+ m_xComponentContext->getValueByName(
+ ("/singletons/"
+ "com.sun.star.java.theJavaVirtualMachine")),
+ UNO_QUERY_THROW);
+
+ // Use the special protocol of XJavaVM.getJavaVM: If the passed in
+ // process ID has an extra 17th byte of value one, the returned any
+ // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of the
+ // underlying JavaVM pointer:
+ Sequence<sal_Int8> processID(17);
+ rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8 *>(processID.getArray()));
+ processID.getArray()[16] = 1;
+
+ // We get a non-refcounted pointer to a jvmaccess::UnoVirtualMachine
+ // from the XJavaVM service (the pointer is guaranteed to be valid
+ // as long as our reference to the XJavaVM service lasts), and
+ // convert the non-refcounted pointer into a refcounted one
+ // immediately:
+ static_assert(sizeof (sal_Int64)
+ >= sizeof (jvmaccess::UnoVirtualMachine *), "must be at least the same size");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::UnoVirtualMachine * >(nullptr));
+ javaVM_xJavaVM->getJavaVM(processID) >>= nPointer;
+ rtl::Reference< jvmaccess::UnoVirtualMachine > xVirtualMachine(
+ reinterpret_cast< jvmaccess::UnoVirtualMachine * >(nPointer));
+ if (!xVirtualMachine.is())
+ {
+ //throw RuntimeException(
+ // "javaloader error - JavaVirtualMachine service could not provide a VM",
+ // css::uno::Reference<XInterface>());
+ // We must not throw a RuntimeException, because this might end the applications.
+ // It is ok if java components
+ // are not working because the office can be installed without Java support.
+ SAL_WARN("stoc", "getJavaVM returned null");
+ return m_javaLoader; // null-ref
+ }
+
+ try
+ {
+ jvmaccess::VirtualMachine::AttachGuard aGuard2(
+ xVirtualMachine->getVirtualMachine());
+ JNIEnv * pJNIEnv = aGuard2.getEnvironment();
+
+ // instantiate the java JavaLoader
+ jclass jcClassLoader = pJNIEnv->FindClass("java/lang/ClassLoader");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find class java/lang/ClassLoader");
+ jmethodID jmLoadClass = pJNIEnv->GetMethodID(
+ jcClassLoader, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find method java/lang/ClassLoader.loadClass");
+ jvalue arg;
+ arg.l = pJNIEnv->NewStringUTF(
+ "com.sun.star.comp.loader.JavaLoader");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not create string");
+ jclass jcJavaLoader = static_cast< jclass >(
+ pJNIEnv->CallObjectMethodA(
+ static_cast< jobject >(xVirtualMachine->getClassLoader()),
+ jmLoadClass, &arg));
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find class com/sun/star/comp/loader/JavaLoader");
+ jmethodID jmJavaLoader_init = pJNIEnv->GetMethodID(jcJavaLoader, "<init>", "()V");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - instantiation of com.sun.star.comp.loader.JavaLoader failed");
+ jobject joJavaLoader = pJNIEnv->NewObject(jcJavaLoader, jmJavaLoader_init);
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - instantiation of com.sun.star.comp.loader.JavaLoader failed");
+
+ // map the java JavaLoader to this environment
+ OUString sJava("java");
+ uno_getEnvironment(&pJava_environment, sJava.pData,
+ xVirtualMachine.get());
+ if(!pJava_environment)
+ throw RuntimeException(
+ "javaloader error - no Java environment available");
+
+ // why is there no convenient constructor?
+ OUString sCppu_current_lb_name(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
+ uno_getEnvironment(&pUno_environment, sCppu_current_lb_name.pData, nullptr);
+ if(!pUno_environment)
+ throw RuntimeException(
+ "javaloader error - no C++ environment available");
+
+ Mapping java_curr(pJava_environment, pUno_environment);
+ if(!java_curr.is())
+ throw RuntimeException(
+ "javaloader error - no mapping from java to C++ ");
+
+ // release java environment
+ pJava_environment->release(pJava_environment);
+ pJava_environment = nullptr;
+
+ // release uno environment
+ pUno_environment->release(pUno_environment);
+ pUno_environment = nullptr;
+
+ cppu::UnoType<XImplementationLoader>::get().
+ getDescription(reinterpret_cast<typelib_TypeDescription **>(&pType_XImplementationLoader));
+ if(!pType_XImplementationLoader)
+ throw RuntimeException(
+ "javaloader error - no type information for XImplementationLoader");
+
+ m_javaLoader.set(static_cast<XImplementationLoader *>(java_curr.mapInterface(joJavaLoader, pType_XImplementationLoader)));
+ pJNIEnv->DeleteLocalRef( joJavaLoader );
+ if(!m_javaLoader.is())
+ throw RuntimeException(
+ "javaloader error - mapping of java XImplementationLoader to c++ failed");
+
+ typelib_typedescription_release(reinterpret_cast<typelib_TypeDescription *>(pType_XImplementationLoader));
+ pType_XImplementationLoader = nullptr;
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+
+ // set the service manager at the javaloader
+ css::uno::Reference<XInitialization> javaLoader_XInitialization(m_javaLoader, UNO_QUERY_THROW);
+
+ Any any;
+ any <<= m_xComponentContext->getServiceManager();
+
+ javaLoader_XInitialization->initialize(Sequence<Any>(&any, 1));
+ }
+ catch(RuntimeException &) {
+ if(pJava_environment)
+ pJava_environment->release(pJava_environment);
+
+ if(pUno_environment)
+ pUno_environment->release(pUno_environment);
+
+ if(pType_XImplementationLoader)
+ typelib_typedescription_release(
+ reinterpret_cast<typelib_TypeDescription *>(pType_XImplementationLoader));
+ throw;
+ }
+ SAL_INFO("stoc", "javaloader.cxx: mapped javaloader - 0x" << m_javaLoader.get());
+ return m_javaLoader;
+}
+
+JavaComponentLoader::JavaComponentLoader(const css::uno::Reference<XComponentContext> & xCtx)
+ : WeakComponentImplHelper(m_aMutex)
+ , m_xComponentContext(xCtx)
+{
+
+}
+
+// XServiceInfo
+OUString SAL_CALL JavaComponentLoader::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.JavaComponentLoader";
+}
+
+sal_Bool SAL_CALL JavaComponentLoader::supportsService(const OUString & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL JavaComponentLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.loader.Java", "com.sun.star.loader.Java2" };
+}
+
+
+// XImplementationLoader
+sal_Bool SAL_CALL JavaComponentLoader::writeRegistryInfo(
+ const css::uno::Reference<XRegistryKey> & xKey, const OUString & blabla,
+ const OUString & rLibName)
+{
+ OUString remoteArg(blabla);
+ const css::uno::Reference<XImplementationLoader> & loader = getJavaLoader(remoteArg);
+ if (!loader.is())
+ throw CannotRegisterImplementationException("Could not create Java implementation loader");
+ return loader->writeRegistryInfo(xKey, remoteArg, rLibName);
+}
+
+css::uno::Reference<XInterface> SAL_CALL JavaComponentLoader::activate(
+ const OUString & rImplName, const OUString & blabla, const OUString & rLibName,
+ const css::uno::Reference<XRegistryKey> & xKey)
+{
+ OUString remoteArg(blabla);
+ if (rImplName.isEmpty() && blabla.isEmpty() && rLibName.isEmpty())
+ {
+ // preload JVM was requested
+ (void)getJavaLoader(remoteArg);
+ return css::uno::Reference<XInterface>();
+ }
+
+ const css::uno::Reference<XImplementationLoader> & loader = getJavaLoader(remoteArg);
+ if (!loader.is())
+ throw CannotActivateFactoryException("Could not create Java implementation loader");
+ return loader->activate(rImplName, remoteArg, rLibName, xKey);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_JavaComponentLoader_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ try {
+ return cppu::acquire(new JavaComponentLoader(context));
+ }
+ catch(const RuntimeException & runtimeException) {
+ SAL_INFO(
+ "stoc",
+ "could not init javaloader due to " << runtimeException);
+ throw;
+ }
+}
+
+} //end namespace
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/interact.cxx b/stoc/source/javavm/interact.cxx
new file mode 100644
index 000000000..d1399c065
--- /dev/null
+++ b/stoc/source/javavm/interact.cxx
@@ -0,0 +1,107 @@
+/* -*- 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 "interact.hxx"
+
+#include <com/sun/star/task/XInteractionAbort.hpp>
+#include <com/sun/star/task/XInteractionRetry.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <mutex>
+
+namespace com::sun::star::task { class XInteractionContinuation; }
+
+using stoc_javavm::InteractionRequest;
+
+namespace {
+
+class AbortContinuation:
+ public cppu::WeakImplHelper<css::task::XInteractionAbort>
+{
+public:
+ AbortContinuation() {}
+ AbortContinuation(const AbortContinuation&) = delete;
+ AbortContinuation& operator=(const AbortContinuation&)= delete;
+
+ virtual void SAL_CALL select() override {}
+
+private:
+ virtual ~AbortContinuation() override {}
+};
+
+}
+
+class InteractionRequest::RetryContinuation:
+ public cppu::WeakImplHelper<css::task::XInteractionRetry>
+{
+public:
+ RetryContinuation(): m_bSelected(false) {}
+ RetryContinuation(const RetryContinuation&) = delete;
+ RetryContinuation& operator=(const RetryContinuation&) = delete;
+
+ virtual void SAL_CALL select() override;
+
+ bool isSelected() const;
+
+private:
+ virtual ~RetryContinuation() override {}
+
+ mutable std::mutex m_aMutex;
+ bool m_bSelected;
+};
+
+void SAL_CALL InteractionRequest::RetryContinuation::select()
+{
+ std::scoped_lock aGuard(m_aMutex);
+ m_bSelected = true;
+}
+
+bool InteractionRequest::RetryContinuation::isSelected() const
+{
+ std::scoped_lock aGuard(m_aMutex);
+ return m_bSelected;
+}
+
+InteractionRequest::InteractionRequest(css::uno::Any const & rRequest):
+ m_aRequest(rRequest)
+{
+ m_xRetryContinuation = new RetryContinuation;
+ m_aContinuations = { new AbortContinuation, m_xRetryContinuation };
+}
+
+css::uno::Any SAL_CALL InteractionRequest::getRequest()
+{
+ return m_aRequest;
+}
+
+css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >
+SAL_CALL InteractionRequest::getContinuations()
+{
+ return m_aContinuations;
+}
+
+bool InteractionRequest::retry() const
+{
+ return m_xRetryContinuation.is() && m_xRetryContinuation->isSelected();
+}
+
+InteractionRequest::~InteractionRequest()
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/interact.hxx b/stoc/source/javavm/interact.hxx
new file mode 100644
index 000000000..35aa97b97
--- /dev/null
+++ b/stoc/source/javavm/interact.hxx
@@ -0,0 +1,67 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_STOC_SOURCE_JAVAVM_INTERACT_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_INTERACT_HXX
+
+#include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::task {
+ class XInteractionContinuation;
+}
+
+namespace stoc_javavm {
+
+class InteractionRequest:
+ public cppu::WeakImplHelper< css::task::XInteractionRequest >
+{
+public:
+ explicit InteractionRequest(css::uno::Any const & rRequest);
+
+ virtual css::uno::Any SAL_CALL getRequest() override;
+
+ virtual css::uno::Sequence< css::uno::Reference<
+ css::task::XInteractionContinuation > > SAL_CALL
+ getContinuations() override;
+
+ bool retry() const;
+
+private:
+ class RetryContinuation;
+
+ InteractionRequest(InteractionRequest const &) = delete;
+ void operator =(const InteractionRequest&) = delete;
+
+ virtual ~InteractionRequest() override;
+
+ css::uno::Any m_aRequest;
+ css::uno::Sequence< css::uno::Reference<
+ css::task::XInteractionContinuation > > m_aContinuations;
+ rtl::Reference< RetryContinuation > m_xRetryContinuation;
+};
+
+}
+
+#endif // INCLUDED_STOC_SOURCE_JAVAVM_INTERACT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/javavm.component b/stoc/source/javavm/javavm.component
new file mode 100644
index 000000000..71379052b
--- /dev/null
+++ b/stoc/source/javavm/javavm.component
@@ -0,0 +1,28 @@
+<?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.JavaVirtualMachine"
+ constructor="stoc_JavaVM_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.java.JavaVirtualMachine"/>
+ <singleton name="com.sun.star.java.theJavaVirtualMachine"/>
+ </implementation>
+</component>
diff --git a/stoc/source/javavm/javavm.cxx b/stoc/source/javavm/javavm.cxx
new file mode 100644
index 000000000..4ed1293f9
--- /dev/null
+++ b/stoc/source/javavm/javavm.cxx
@@ -0,0 +1,1483 @@
+/* -*- 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 "javavm.hxx"
+
+#include "interact.hxx"
+#include "jvmargs.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/java/JavaNotFoundException.hpp>
+#include <com/sun/star/java/InvalidJavaSettingsException.hpp>
+#include <com/sun/star/java/RestartRequiredException.hpp>
+#include <com/sun/star/java/JavaDisabledException.hpp>
+#include <com/sun/star/java/JavaVMCreationFailureException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <jvmaccess/classpath.hxx>
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+#include <rtl/process.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <sal/log.hxx>
+#include <uno/current_context.hxx>
+#include <jvmfwk/framework.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <jni.h>
+
+#include <stack>
+#include <string.h>
+#include <time.h>
+#include <memory>
+#include <vector>
+
+// Properties of the javavm can be put
+// as a comma separated list in this
+// environment variable
+#ifdef UNIX
+#define TIMEZONE "MEZ"
+#else
+#define TIMEZONE "MET"
+#endif
+
+/* Within this implementation of the com.sun.star.java.JavaVirtualMachine
+ * service and com.sun.star.java.theJavaVirtualMachine singleton, the method
+ * com.sun.star.java.XJavaVM.getJavaVM relies on the following:
+ * 1 The string "$URE_INTERNAL_JAVA_DIR/" is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into an internal (see the
+ * com.sun.star.uri.ExternalUriReferenceTranslator service), hierarchical URI
+ * reference relative to which the URE JAR files can be addressed.
+ * 2 The string "$URE_INTERNAL_JAVA_CLASSPATH" is either not expandable via the
+ * com.sun.star.util.theMacroExpander singleton
+ * (com.sun.star.lang.IllegalArgumentException), or is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into a list of zero or more
+ * internal (see the com.sun.star.uri.ExternalUriReferenceTranslator service)
+ * URIs, where any space characters (U+0020) are ignored (and, in particular,
+ * separate adjacent URIs).
+ * If either of these requirements is not met, getJavaVM raises a
+ * com.sun.star.uno.RuntimeException.
+ */
+
+using stoc_javavm::JavaVirtualMachine;
+
+namespace {
+
+
+class NoJavaIniException: public css::uno::Exception
+{
+};
+
+typedef std::stack< jvmaccess::VirtualMachine::AttachGuard * > GuardStack;
+
+extern "C" {
+
+static void destroyAttachGuards(void * pData)
+{
+ GuardStack * pStack = static_cast< GuardStack * >(pData);
+ if (pStack != nullptr)
+ {
+ while (!pStack->empty())
+ {
+ delete pStack->top();
+ pStack->pop();
+ }
+ delete pStack;
+ }
+}
+
+}
+
+bool askForRetry(css::uno::Any const & rException)
+{
+ css::uno::Reference< css::uno::XCurrentContext > xContext(
+ css::uno::getCurrentContext());
+ if (xContext.is())
+ {
+ css::uno::Reference< css::task::XInteractionHandler > xHandler;
+ xContext->getValueByName("java-vm.interaction-handler")
+ >>= xHandler;
+ if (xHandler.is())
+ {
+ rtl::Reference< stoc_javavm::InteractionRequest > xRequest(
+ new stoc_javavm::InteractionRequest(rException));
+ xHandler->handle(xRequest);
+ return xRequest->retry();
+ }
+ }
+ return false;
+}
+
+// Only gets the properties if the "Proxy Server" entry in the option dialog is
+// set to manual (i.e. not to none)
+/// @throws css::uno::Exception
+void getINetPropsFromConfig(stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry = xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx );
+ if(!xConfRegistry.is()) throw css::uno::RuntimeException("javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Inet", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+// if ooInetProxyType is not 0 then read the settings
+ css::uno::Reference<css::registry::XRegistryKey> proxyEnable= xRegistryRootKey->openKey("Settings/ooInetProxyType");
+ if( proxyEnable.is() && 0 != proxyEnable->getLongValue())
+ {
+ // read ftp proxy name
+ css::uno::Reference<css::registry::XRegistryKey> ftpProxy_name = xRegistryRootKey->openKey("Settings/ooInetFTPProxyName");
+ if(ftpProxy_name.is() && !ftpProxy_name->getStringValue().isEmpty()) {
+ OUString ftpHost = "ftp.proxyHost=" + ftpProxy_name->getStringValue();
+
+ // read ftp proxy port
+ css::uno::Reference<css::registry::XRegistryKey> ftpProxy_port = xRegistryRootKey->openKey("Settings/ooInetFTPProxyPort");
+ if(ftpProxy_port.is() && ftpProxy_port->getLongValue()) {
+ OUString ftpPort = "ftp.proxyPort=" + OUString::number(ftpProxy_port->getLongValue());
+
+ pjvm->pushProp(ftpHost);
+ pjvm->pushProp(ftpPort);
+ }
+ }
+
+ // read http proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyName");
+ if(httpProxy_name.is() && !httpProxy_name->getStringValue().isEmpty()) {
+ OUString httpHost = "http.proxyHost=" + httpProxy_name->getStringValue();
+
+ // read http proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyPort");
+ if(httpProxy_port.is() && httpProxy_port->getLongValue()) {
+ OUString httpPort = "http.proxyPort=" + OUString::number(httpProxy_port->getLongValue());
+
+ pjvm->pushProp(httpHost);
+ pjvm->pushProp(httpPort);
+ }
+ }
+
+ // read https proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyName");
+ if(httpsProxy_name.is() && !httpsProxy_name->getStringValue().isEmpty()) {
+ OUString httpsHost = "https.proxyHost=" + httpsProxy_name->getStringValue();
+
+ // read https proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyPort");
+ if(httpsProxy_port.is() && httpsProxy_port->getLongValue()) {
+ OUString httpsPort = "https.proxyPort=" + OUString::number(httpsProxy_port->getLongValue());
+
+ pjvm->pushProp(httpsHost);
+ pjvm->pushProp(httpsPort);
+ }
+ }
+
+ // read nonProxyHosts
+ css::uno::Reference<css::registry::XRegistryKey> nonProxies_name = xRegistryRootKey->openKey("Settings/ooInetNoProxy");
+ if(nonProxies_name.is() && !nonProxies_name->getStringValue().isEmpty()) {
+ OUString value = nonProxies_name->getStringValue();
+ // replace the separator ";" by "|"
+ value = value.replace(';', '|');
+
+ OUString httpNonProxyHosts = "http.nonProxyHosts=" + value;
+ OUString ftpNonProxyHosts = "ftp.nonProxyHosts=" + value;
+
+ pjvm->pushProp(httpNonProxyHosts);
+ pjvm->pushProp(ftpNonProxyHosts);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getDefaultLocaleFromConfig(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext( "com.sun.star.configuration.ConfigurationRegistry", xCtx );
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Setup", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+ // Since 1.7 Java knows DISPLAY and FORMAT locales, which match our UI and
+ // system locale. See
+ // http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/569b1b644416/src/share/classes/java/util/Locale.java
+ // https://docs.oracle.com/javase/tutorial/i18n/locale/scope.html
+ // https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html
+
+ // Read UI language/locale.
+ css::uno::Reference<css::registry::XRegistryKey> xUILocale = xRegistryRootKey->openKey("L10N/ooLocale");
+ if(xUILocale.is() && !xUILocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xUILocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ if(!language.isEmpty()) {
+ OUString prop = "user.language=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ // As of Java 7 also script is supported.
+ if(!script.isEmpty()) {
+ OUString prop = "user.script=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country=" + country;
+ pjvm->pushProp(prop);
+ }
+
+ // Java 7 DISPLAY category is our UI language/locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.display=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.display=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.display=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ // Read system locale.
+ css::uno::Reference<css::registry::XRegistryKey> xLocale = xRegistryRootKey->openKey("L10N/ooSetupSystemLocale");
+ if(xLocale.is() && !xLocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xLocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ // Java 7 FORMAT category is our system locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.format=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.format=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.format=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getJavaPropsFromSafetySettings(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx)
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx);
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open(
+ "org.openoffice.Office.Java",
+ true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey =
+ xConfRegistry_simple->getRootKey();
+
+ if (xRegistryRootKey.is())
+ {
+ css::uno::Reference<css::registry::XRegistryKey> key_NetAccess= xRegistryRootKey->openKey("VirtualMachine/NetAccess");
+ if (key_NetAccess.is())
+ {
+ sal_Int32 val= key_NetAccess->getLongValue();
+ OUString sVal;
+ switch( val)
+ {
+ case 0: sVal = "host";
+ break;
+ case 1: sVal = "unrestricted";
+ break;
+ case 3: sVal = "none";
+ break;
+ }
+ OUString sProperty = "appletviewer.security.mode=" + sVal;
+ pjvm->pushProp(sProperty);
+ }
+ css::uno::Reference<css::registry::XRegistryKey> key_CheckSecurity= xRegistryRootKey->openKey(
+ "VirtualMachine/Security");
+ if( key_CheckSecurity.is())
+ {
+ bool val = static_cast<bool>(key_CheckSecurity->getLongValue());
+ OUString sProperty("stardiv.security.disableSecurity=");
+ if( val)
+ sProperty += "false";
+ else
+ sProperty += "true";
+ pjvm->pushProp( sProperty);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+void setTimeZone(stoc_javavm::JVM * pjvm) noexcept {
+ /* A Bug in the Java function
+ ** struct Hjava_util_Properties * java_lang_System_initProperties(
+ ** struct Hjava_lang_System *this,
+ ** struct Hjava_util_Properties *props);
+ ** This function doesn't detect MEZ, MET or "W. Europe Standard Time"
+ */
+ struct tm *tmData;
+ time_t clock = time(nullptr);
+ tzset();
+ tmData = localtime(&clock);
+#ifdef MACOSX
+ char * p = tmData->tm_zone;
+#elif defined(_MSC_VER)
+ char * p = _tzname[0];
+ (void)tmData;
+#else
+ char * p = tzname[0];
+ (void)tmData;
+#endif
+
+ if (!strcmp(TIMEZONE, p))
+ pjvm->pushProp("user.timezone=ECT");
+}
+
+/// @throws css::uno::Exception
+void initVMConfiguration(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext > &xCtx)
+{
+ stoc_javavm::JVM jvm;
+ try {
+ getINetPropsFromConfig(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "can not get INETProps because of " << exception);
+ }
+
+ try {
+ getDefaultLocaleFromConfig(&jvm, xSMgr,xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "can not get locale because of " << exception);
+ }
+
+ try
+ {
+ getJavaPropsFromSafetySettings(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "couldn't get safety settings because of " << exception);
+ }
+
+ *pjvm= jvm;
+
+ // rhbz#1285356, native look will be gtk2, which crashes
+ // when gtk3 is already loaded. Until there is a solution
+ // java-side force look and feel to something that doesn't
+ // crash when we are using gtk3
+ if (getenv("STOC_FORCE_SYSTEM_LAF"))
+ pjvm->pushProp("swing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel");
+
+ setTimeZone(pjvm);
+}
+
+class DetachCurrentThread {
+public:
+ explicit DetachCurrentThread(JavaVM * jvm): m_jvm(jvm) {}
+
+ ~DetachCurrentThread() {
+ if (m_jvm->DetachCurrentThread() != 0) {
+ OSL_ASSERT(false);
+ }
+ }
+
+ DetachCurrentThread(const DetachCurrentThread&) = delete;
+ DetachCurrentThread& operator=(const DetachCurrentThread&) = delete;
+
+private:
+ JavaVM * m_jvm;
+};
+
+}
+
+JavaVirtualMachine::JavaVirtualMachine(
+ css::uno::Reference< css::uno::XComponentContext > const & rContext):
+ WeakComponentImplHelper(m_aMutex),
+ m_xContext(rContext),
+ m_bDisposed(false),
+ m_pJavaVm(nullptr),
+ m_aAttachGuards(destroyAttachGuards) // TODO check for validity
+{}
+
+void SAL_CALL
+JavaVirtualMachine::initialize(css::uno::Sequence< css::uno::Any > const &
+ rArguments)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "bad call to initialize",
+ static_cast< cppu::OWeakObject * >(this));
+ css::beans::NamedValue val;
+ if (rArguments.getLength() == 1 && (rArguments[0] >>= val) && val.Name == "UnoVirtualMachine" )
+ {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::UnoVirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::UnoVirtualMachine * >(nullptr));
+ val.Value >>= nPointer;
+ m_xUnoVirtualMachine =
+ reinterpret_cast< jvmaccess::UnoVirtualMachine * >(nPointer);
+ } else {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::VirtualMachine * >(nullptr));
+ if (rArguments.getLength() == 1)
+ rArguments[0] >>= nPointer;
+ rtl::Reference< jvmaccess::VirtualMachine > vm(
+ reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer));
+ if (vm.is()) {
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(vm, nullptr);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ throw css::lang::IllegalArgumentException(
+ "sequence of exactly one any containing either (a) a"
+ " com.sun.star.beans.NamedValue with Name"
+ " \"UnoVirtualMachine\" and Value a hyper representing a"
+ " non-null pointer to a jvmaccess:UnoVirtualMachine, or (b)"
+ " a hyper representing a non-null pointer to a"
+ " jvmaccess::VirtualMachine required",
+ static_cast< cppu::OWeakObject * >(this), 0);
+ }
+ m_xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+}
+
+OUString SAL_CALL JavaVirtualMachine::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.JavaVirtualMachine";
+}
+
+sal_Bool SAL_CALL
+JavaVirtualMachine::supportsService(OUString const & rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL
+JavaVirtualMachine::getSupportedServiceNames()
+{
+ return { "com.sun.star.java.JavaVirtualMachine" };
+}
+
+css::uno::Any SAL_CALL
+JavaVirtualMachine::getJavaVM(css::uno::Sequence< sal_Int8 > const & rProcessId)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ css::uno::Sequence< sal_Int8 > aId(16);
+ rtl_getGlobalProcessId(reinterpret_cast< sal_uInt8 * >(aId.getArray()));
+ enum ReturnType {
+ RETURN_JAVAVM, RETURN_VIRTUALMACHINE, RETURN_UNOVIRTUALMACHINE };
+ ReturnType returnType =
+ rProcessId.getLength() == 17 && rProcessId[16] == 0
+ ? RETURN_VIRTUALMACHINE
+ : rProcessId.getLength() == 17 && rProcessId[16] == 1
+ ? RETURN_UNOVIRTUALMACHINE
+ : RETURN_JAVAVM;
+ css::uno::Sequence< sal_Int8 > aProcessId(rProcessId);
+ if (returnType != RETURN_JAVAVM)
+ aProcessId.realloc(16);
+ if (aId != aProcessId)
+ return css::uno::Any();
+
+ std::unique_ptr<JavaInfo> info;
+ while (!m_xVirtualMachine.is()) // retry until successful
+ {
+ stoc_javavm::JVM aJvm;
+ initVMConfiguration(&aJvm, m_xContext->getServiceManager(),
+ m_xContext);
+ const std::vector<OUString> & props = aJvm.getProperties();
+ std::vector<OUString> options;
+ options.reserve(props.size());
+ for (auto const& i : props)
+ {
+ options.push_back(i.startsWith("-") ? i : "-D" + i);
+ }
+
+ JNIEnv * pMainThreadEnv = nullptr;
+ javaFrameworkError errcode = JFW_E_NONE;
+
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errcode = JFW_E_NO_SELECT;
+ else
+ errcode = jfw_startVM(info.get(), options, & m_pJavaVm,
+ & pMainThreadEnv);
+
+ bool bStarted = false;
+ switch (errcode)
+ {
+ case JFW_E_NONE: bStarted = true; break;
+ case JFW_E_NO_SELECT:
+ {
+ // No Java configured. We silently run the Java configuration
+ info.reset();
+ javaFrameworkError errFind = jfw_findAndSelectJRE(&info);
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errFind = JFW_E_NO_JAVA_FOUND;
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ else if (errFind == JFW_E_NO_JAVA_FOUND)
+ {
+
+ //Warning MessageBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform this task.
+ //Please install a JRE and restart %PRODUCTNAME.
+ css::java::JavaNotFoundException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " No suitable JRE found!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ else
+ {
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while searching for a Java, " + OUString::number(errFind), nullptr);
+ }
+ }
+ case JFW_E_INVALID_SETTINGS:
+ {
+ //Warning MessageBox:
+ // The %PRODUCTNAME configuration has been changed. Under Tools
+ // - Options - %PRODUCTNAME - Java, select the Java runtime environment
+ // you want to have used by %PRODUCTNAME.
+ css::java::InvalidJavaSettingsException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " Java settings have changed!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_JAVA_DISABLED:
+ {
+ if (comphelper::IsContextFlagActive("DontEnableJava"))
+ return css::uno::Any();
+
+ //QueryBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform
+ //this task. However, use of a JRE has been disabled. Do you want to
+ //enable the use of a JRE now?
+ css::java::JavaDisabledException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is disabled!",
+ static_cast< cppu::OWeakObject * >(this));
+ if( ! askForRetry(css::uno::Any(exc)))
+ return css::uno::Any();
+ continue;
+ }
+ case JFW_E_VM_CREATION_FAILED:
+ {
+ //If the creation failed because the JRE has been uninstalled then
+ //we search another one. As long as there is a javaldx, we should
+ //never come into this situation. javaldx checks always if the JRE
+ //still exist.
+ std::unique_ptr<JavaInfo> aJavaInfo;
+ if (JFW_E_NONE == jfw_getSelectedJRE(&aJavaInfo))
+ {
+ bool bExist = false;
+ if (JFW_E_NONE == jfw_existJRE(aJavaInfo.get(), &bExist))
+ {
+ if (!bExist
+ && ! (aJavaInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
+ {
+ info.reset();
+ javaFrameworkError errFind = jfw_findAndSelectJRE(
+ &info);
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ }
+ }
+ }
+
+ //Error: %PRODUCTNAME requires a Java
+ //runtime environment (JRE) to perform this task. The selected JRE
+ //is defective. Please select another version or install a new JRE
+ //and select it under Tools - Options - %PRODUCTNAME - Java.
+ css::java::JavaVMCreationFailureException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is defective!",
+ static_cast< cppu::OWeakObject * >(this), 0);
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_RUNNING_JVM:
+ {
+ //This service should make sure that we do not start java twice.
+ OSL_ASSERT(false);
+ break;
+ }
+ case JFW_E_NEED_RESTART:
+ {
+ //Error:
+ //For the selected Java runtime environment to work properly,
+ //%PRODUCTNAME must be restarted. Please restart %PRODUCTNAME now.
+ css::java::RestartRequiredException exc(
+ "JavaVirtualMachine::getJavaVM failed because "
+ "Office must be restarted before Java can be used!",
+ static_cast< cppu::OWeakObject * >(this));
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ default:
+ //RuntimeException: error is somewhere in the java framework.
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while starting Java!", nullptr);
+ }
+
+ if (bStarted)
+ {
+ {
+ DetachCurrentThread detach(m_pJavaVm);
+ // necessary to make debugging work; this thread will be
+ // suspended when the destructor of detach returns
+ m_xVirtualMachine = new jvmaccess::VirtualMachine(
+ m_pJavaVm, JNI_VERSION_1_2, true, pMainThreadEnv);
+ setUpUnoVirtualMachine(pMainThreadEnv);
+ }
+ // Listen for changes in the configuration (e.g. proxy settings):
+ // TODO this is done too late; changes to the configuration done
+ // after the above call to initVMConfiguration are lost
+ registerConfigChangesListener();
+
+ break;
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ try {
+ jvmaccess::VirtualMachine::AttachGuard guard(m_xVirtualMachine);
+ setUpUnoVirtualMachine(guard.getEnvironment());
+ } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException occurred",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ }
+ switch (returnType) {
+ default: // RETURN_JAVAVM
+ if (m_pJavaVm == nullptr) {
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine service was initialized in a way"
+ " that the requested JavaVM pointer is not available",
+ static_cast< cppu::OWeakObject * >(this));
+ }
+ return css::uno::Any(reinterpret_cast< sal_IntPtr >(m_pJavaVm));
+ case RETURN_VIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::Any(
+ reinterpret_cast< sal_Int64 >(
+ m_xUnoVirtualMachine->getVirtualMachine().get()));
+ case RETURN_UNOVIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::Any(
+ reinterpret_cast< sal_Int64 >(m_xUnoVirtualMachine.get()));
+ }
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMStarted()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ return m_xUnoVirtualMachine.is();
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMEnabled()
+{
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ }
+// stoc_javavm::JVM aJvm;
+// initVMConfiguration(&aJvm, m_xContext->getServiceManager(), m_xContext);
+// return aJvm.isEnabled();
+ //ToDo
+ bool bEnabled = false;
+ if (jfw_getEnabled( & bEnabled) != JFW_E_NONE)
+ throw css::uno::RuntimeException();
+ return bEnabled;
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isThreadAttached()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), static_cast< cppu::OWeakObject * >(this));
+ // TODO isThreadAttached only returns true if the thread was attached via
+ // registerThread:
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ return pStack != nullptr && !pStack->empty();
+}
+
+void SAL_CALL JavaVirtualMachine::registerThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::registerThread: null VirtualMachine",
+ static_cast< cppu::OWeakObject * >(this));
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr)
+ {
+ pStack = new GuardStack;
+ m_aAttachGuards.setData(pStack);
+ }
+ try
+ {
+ pStack->push(
+ new jvmaccess::VirtualMachine::AttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine()));
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "JavaVirtualMachine::registerThread: jvmaccess::"
+ "VirtualMachine::AttachGuard::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::revokeThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", static_cast< cppu::OWeakObject * >(this));
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: null VirtualMachine",
+ static_cast< cppu::OWeakObject * >(this));
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr || pStack->empty())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: no matching registerThread",
+ static_cast< cppu::OWeakObject * >(this));
+ delete pStack->top();
+ pStack->pop();
+}
+
+void SAL_CALL
+JavaVirtualMachine::disposing(css::lang::EventObject const & rSource)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (rSource.Source == m_xInetConfiguration)
+ m_xInetConfiguration.clear();
+ if (rSource.Source == m_xJavaConfiguration)
+ m_xJavaConfiguration.clear();
+}
+
+void SAL_CALL JavaVirtualMachine::elementInserted(
+ css::container::ContainerEvent const &)
+{}
+
+void SAL_CALL JavaVirtualMachine::elementRemoved(
+ css::container::ContainerEvent const &)
+{}
+
+// If a user changes the setting, for example for proxy settings, then this
+// function will be called from the configuration manager. Even if the .xml
+// file does not contain an entry yet and that entry has to be inserted, this
+// function will be called. We call java.lang.System.setProperty for the new
+// values.
+void SAL_CALL JavaVirtualMachine::elementReplaced(
+ css::container::ContainerEvent const & rEvent)
+{
+ // TODO Using the new value stored in rEvent is wrong here. If two threads
+ // receive different elementReplaced calls in quick succession, it is
+ // unspecified which changes the JVM's system properties last. A correct
+ // solution must atomically (i.e., protected by a mutex) read the latest
+ // value from the configuration and set it as a system property at the JVM.
+
+ OUString aAccessor;
+ rEvent.Accessor >>= aAccessor;
+ OUString aPropertyName;
+ OUString aPropertyName2;
+ OUString aPropertyValue;
+ bool bSecurityChanged = false;
+ if ( aAccessor == "ooInetProxyType" )
+ {
+ // Proxy none, manually
+ sal_Int32 value = 0;
+ rEvent.Element >>= value;
+ setINetSettingsInVM(value != 0);
+ return;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyName" )
+ {
+ aPropertyName = "http.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyPort" )
+ {
+ aPropertyName = "http.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyName" )
+ {
+ aPropertyName = "https.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyPort" )
+ {
+ aPropertyName = "https.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetFTPProxyName" )
+ {
+ aPropertyName = "ftp.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetFTPProxyPort" )
+ {
+ aPropertyName = "ftp.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetNoProxy" )
+ {
+ aPropertyName = "http.nonProxyHosts";
+ aPropertyName2 = "ftp.nonProxyHosts";
+ rEvent.Element >>= aPropertyValue;
+ aPropertyValue = aPropertyValue.replace(';', '|');
+ }
+ else if ( aAccessor == "NetAccess" )
+ {
+ aPropertyName = "appletviewer.security.mode";
+ sal_Int32 n = 0;
+ if (rEvent.Element >>= n)
+ switch (n)
+ {
+ case 0:
+ aPropertyValue = "host";
+ break;
+ case 1:
+ aPropertyValue = "unrestricted";
+ break;
+ case 3:
+ aPropertyValue = "none";
+ break;
+ }
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else if ( aAccessor == "Security" )
+ {
+ aPropertyName = "stardiv.security.disableSecurity";
+ bool b;
+ if (rEvent.Element >>= b)
+ if (b)
+ aPropertyValue = "false";
+ else
+ aPropertyValue = "true";
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else
+ return;
+
+ rtl::Reference< jvmaccess::VirtualMachine > xVirtualMachine;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_xUnoVirtualMachine.is()) {
+ xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+ }
+ }
+ if (!xVirtualMachine.is())
+ return;
+
+ try
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ xVirtualMachine);
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // call java.lang.System.setProperty
+ // String setProperty( String key, String value)
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ jstring jsPropName= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName.getStr()), aPropertyName.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // remove the property if it does not have a value ( user left the dialog field empty)
+ // or if the port is set to 0
+ aPropertyValue= aPropertyValue.trim();
+ if( aPropertyValue.isEmpty() ||
+ ( ( aPropertyName == "ftp.proxyPort" || aPropertyName == "http.proxyPort" /*|| aPropertyName == "socksProxyPort"*/ ) && aPropertyValue == "0" )
+ )
+ {
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // call java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Properties.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsPropName);
+
+ // special case for ftp.nonProxyHosts and http.nonProxyHosts. The office only
+ // has a value for two java properties
+ if (!aPropertyName2.isEmpty())
+ {
+ jstring jsPropName2= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName2.getStr()), aPropertyName2.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsPropName2);
+ }
+ }
+ else
+ {
+ // Change the Value of the property
+ jstring jsPropValue= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyValue.getStr()), aPropertyValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsPropName, jsPropValue);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+
+ // special case for ftp.nonProxyHosts and http.nonProxyHosts. The office only
+ // has a value for two java properties
+ if (!aPropertyName2.isEmpty())
+ {
+ jstring jsPropName2= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName2.getStr()), aPropertyName2.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jsPropValue= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyValue.getStr()), aPropertyValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsPropName2, jsPropValue);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ }
+
+ // If the settings for Security and NetAccess changed then we have to notify the SandboxSecurity
+ // SecurityManager
+ // call System.getSecurityManager()
+ if (bSecurityChanged)
+ {
+ jmethodID jmGetSecur= pJNIEnv->GetStaticMethodID( jcSystem,"getSecurityManager","()Ljava/lang/SecurityManager;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getSecurityManager", nullptr);
+ jobject joSecur= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetSecur);
+ if (joSecur != nullptr)
+ {
+ // Make sure the SecurityManager is our SandboxSecurity
+ // FindClass("com.sun.star.lib.sandbox.SandboxSecurityManager" only worked at the first time
+ // this code was executed. Maybe it is a security feature. However, all attempts to debug the
+ // SandboxSecurity class (maybe the VM invokes checkPackageAccess) failed.
+// jclass jcSandboxSec= pJNIEnv->FindClass("com.sun.star.lib.sandbox.SandboxSecurity");
+// if(pJNIEnv->ExceptionOccurred()) throw RuntimeException("JNI:FindClass com.sun.star.lib.sandbox.SandboxSecurity");
+// jboolean bIsSand= pJNIEnv->IsInstanceOf( joSecur, jcSandboxSec);
+ // The SecurityManagers class Name must be com.sun.star.lib.sandbox.SandboxSecurity
+ jclass jcSec= pJNIEnv->GetObjectClass( joSecur);
+ jclass jcClass= pJNIEnv->FindClass("java/lang/Class");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java.lang.Class", nullptr);
+ jmethodID jmName= pJNIEnv->GetMethodID( jcClass,"getName","()Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.lang.Class.getName", nullptr);
+ jstring jsClass= static_cast<jstring>(pJNIEnv->CallObjectMethod( jcSec, jmName));
+ const jchar* jcharName= pJNIEnv->GetStringChars( jsClass, nullptr);
+ OUString sName(reinterpret_cast<sal_Unicode const *>(jcharName));
+ bool bIsSandbox;
+ bIsSandbox = sName == "com.sun.star.lib.sandbox.SandboxSecurity";
+ pJNIEnv->ReleaseStringChars( jsClass, jcharName);
+
+ if (bIsSandbox)
+ {
+ // call SandboxSecurity.reset
+ jmethodID jmReset= pJNIEnv->GetMethodID( jcSec,"reset","()V");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ pJNIEnv->CallVoidMethod( joSecur, jmReset);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallVoidMethod com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ }
+ }
+ }
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+JavaVirtualMachine::~JavaVirtualMachine()
+{
+ if (m_xInetConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xInetConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+ if (m_xJavaConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xJavaConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::disposing()
+{
+ css::uno::Reference< css::container::XContainer > xContainer1;
+ css::uno::Reference< css::container::XContainer > xContainer2;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ m_bDisposed = true;
+ xContainer1 = m_xInetConfiguration;
+ m_xInetConfiguration.clear();
+ xContainer2 = m_xJavaConfiguration;
+ m_xJavaConfiguration.clear();
+ }
+ if (xContainer1.is())
+ xContainer1->removeContainerListener(this);
+ if (xContainer2.is())
+ xContainer2->removeContainerListener(this);
+}
+
+/*We listen to changes in the configuration. For example, the user changes the proxy
+ settings in the options dialog (menu tools). Then we are notified of this change and
+ if the java vm is already running we change the properties (System.lang.System.setProperties)
+ through JNI.
+ To receive notifications this class implements XContainerListener.
+*/
+void JavaVirtualMachine::registerConfigChangesListener()
+{
+ try
+ {
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
+ m_xContext->getValueByName(
+ "/singletons/com.sun.star.configuration.theDefaultProvider"),
+ css::uno::UNO_QUERY);
+
+ if (xConfigProvider.is())
+ {
+ // We register this instance as listener to changes in org.openoffice.Inet/Settings
+ // arguments for ConfigurationAccess
+ css::uno::Sequence<css::uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Inet/Settings"))},
+ {"depth", css::uno::Any(sal_Int32(-1))}
+ }));
+ m_xInetConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments),
+ css::uno::UNO_QUERY);
+
+ if (m_xInetConfiguration.is())
+ m_xInetConfiguration->addContainerListener(this);
+
+ // now register as listener to changes in org.openoffice.Java/VirtualMachine
+ css::uno::Sequence<css::uno::Any> aArguments2(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Office.Java/VirtualMachine"))},
+ {"depth", css::uno::Any(sal_Int32(-1))} // depth: -1 means unlimited
+ }));
+ m_xJavaConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments2),
+ css::uno::UNO_QUERY);
+
+ if (m_xJavaConfiguration.is())
+ m_xJavaConfiguration->addContainerListener(this);
+ }
+ }catch(const css::uno::Exception & e)
+ {
+ SAL_INFO("stoc", "could not set up listener for Configuration because of >" << e << "<");
+ }
+}
+
+// param true: all Inet setting are set as Java Properties on a live VM.
+// false: the Java net properties are set to empty value.
+void JavaVirtualMachine::setINetSettingsInVM(bool set_reset)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ try
+ {
+ if (m_xUnoVirtualMachine.is())
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine());
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // The Java Properties
+ OUString sFtpProxyHost("ftp.proxyHost");
+ OUString sFtpProxyPort("ftp.proxyPort");
+ OUString sFtpNonProxyHosts ("ftp.nonProxyHosts");
+ OUString sHttpProxyHost("http.proxyHost");
+ OUString sHttpProxyPort("http.proxyPort");
+ OUString sHttpNonProxyHosts("http.nonProxyHosts");
+
+ // create Java Properties as JNI strings
+ jstring jsFtpProxyHost= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpProxyHost.getStr()), sFtpProxyHost.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsFtpProxyPort= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpProxyPort.getStr()), sFtpProxyPort.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsFtpNonProxyHosts= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sFtpNonProxyHosts.getStr()), sFtpNonProxyHosts.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpProxyHost= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyHost.getStr()), sHttpProxyHost.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpProxyPort= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyPort.getStr()), sHttpProxyPort.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpNonProxyHosts= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpNonProxyHosts.getStr()), sHttpNonProxyHosts.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // prepare java.lang.System.setProperty
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // prepare java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+
+ if (set_reset)
+ {
+ // Set all network properties with the VM
+ JVM jvm;
+ getINetPropsFromConfig( &jvm, m_xContext->getServiceManager(), m_xContext);
+ const ::std::vector< OUString> & Props = jvm.getProperties();
+
+ for( auto& prop : Props)
+ {
+ sal_Int32 index= prop.indexOf( '=');
+ std::u16string_view propName= prop.subView( 0, index);
+ OUString propValue= prop.copy( index + 1);
+
+ if( propName == sFtpProxyHost)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpProxyHost, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sFtpProxyPort)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpProxyPort, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sFtpNonProxyHosts)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsFtpNonProxyHosts, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpProxyHost)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyHost, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpProxyPort)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyPort, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpNonProxyHosts)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpNonProxyHosts, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ }
+ }
+ else
+ {
+ // call java.util.Properties.remove
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Property.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpProxyHost);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpProxyPort);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsFtpNonProxyHosts);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyHost);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyPort);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpNonProxyHosts);
+ }
+ }
+ }
+ catch (css::uno::RuntimeException &)
+ {
+ OSL_FAIL("RuntimeException");
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ OSL_FAIL("jvmaccess::VirtualMachine::AttachGuard::CreationException");
+ }
+}
+
+void JavaVirtualMachine::setUpUnoVirtualMachine(JNIEnv * environment) {
+ css::uno::Reference< css::util::XMacroExpander > exp = css::util::theMacroExpander::get(m_xContext);
+ OUString baseUrl;
+ try {
+ baseUrl = exp->expandMacros("$URE_INTERNAL_JAVA_DIR/");
+ } catch (css::lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "css::lang::IllegalArgumentException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+ OUString classPath;
+ try {
+ classPath = exp->expandMacros("$URE_INTERNAL_JAVA_CLASSPATH");
+ } catch (css::lang::IllegalArgumentException &) {}
+ jclass class_URLClassLoader = environment->FindClass(
+ "java/net/URLClassLoader");
+ if (class_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URLClassLoader = environment->GetMethodID(
+ class_URLClassLoader, "<init>", "([Ljava/net/URL;)V");
+ if (ctor_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_URL = environment->FindClass("java/net/URL");
+ if (class_URL == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_1 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/lang/String;)V");
+ if (ctor_URL_1 == nullptr) {
+ handleJniException(environment);
+ }
+ jvalue args[3];
+ args[0].l = environment->NewString(
+ reinterpret_cast< jchar const * >(baseUrl.getStr()),
+ static_cast< jsize >(baseUrl.getLength()));
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject base = environment->NewObjectA(class_URL, ctor_URL_1, args);
+ if (base == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_2 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/net/URL;Ljava/lang/String;)V");
+ if (ctor_URL_2 == nullptr) {
+ handleJniException(environment);
+ }
+ jobjectArray classpath = jvmaccess::ClassPath::translateToUrls(
+ m_xContext, environment, classPath);
+ if (classpath == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = environment->NewStringUTF("unoloader.jar");
+ if (args[1].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectA(class_URL, ctor_URL_2, args);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectArray(1, class_URL, args[0].l);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject cl1 = environment->NewObjectA(
+ class_URLClassLoader, ctor_URLClassLoader, args);
+ if (cl1 == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID method_loadClass = environment->GetMethodID(
+ class_URLClassLoader, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ if (method_loadClass == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewStringUTF(
+ "com.sun.star.lib.unoloader.UnoClassLoader");
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_UnoClassLoader = static_cast< jclass >(
+ environment->CallObjectMethodA(cl1, method_loadClass, args));
+ if (class_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_UnoClassLoader = environment->GetMethodID(
+ class_UnoClassLoader, "<init>",
+ "(Ljava/net/URL;[Ljava/net/URL;Ljava/lang/ClassLoader;)V");
+ if (ctor_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = classpath;
+ args[2].l = cl1;
+ jobject cl2 = environment->NewObjectA(
+ class_UnoClassLoader, ctor_UnoClassLoader, args);
+ if (cl2 == nullptr) {
+ handleJniException(environment);
+ }
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(
+ m_xVirtualMachine, cl2);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ static_cast< cppu::OWeakObject * >(this), anyEx );
+ }
+}
+
+void JavaVirtualMachine::handleJniException(JNIEnv * environment) {
+#if defined DBG_UTIL
+ environment->ExceptionDescribe();
+#else
+ environment->ExceptionClear();
+#endif
+ throw css::uno::RuntimeException(
+ "JNI exception occurred",
+ static_cast< cppu::OWeakObject * >(this));
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_JavaVM_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new JavaVirtualMachine(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/javavm.hxx b/stoc/source/javavm/javavm.hxx
new file mode 100644
index 000000000..e3551b292
--- /dev/null
+++ b/stoc/source/javavm/javavm.hxx
@@ -0,0 +1,147 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/java/XJavaThreadRegister_11.hpp>
+#include <com/sun/star/java/XJavaVM.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <osl/thread.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star {
+ namespace container { class XContainer; }
+ namespace uno { class XComponentContext; }
+}
+namespace jvmaccess {
+ class UnoVirtualMachine;
+ class VirtualMachine;
+}
+
+namespace stoc_javavm {
+
+class JavaVirtualMachine:
+ private cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper<
+ css::lang::XInitialization, css::lang::XServiceInfo, css::java::XJavaVM,
+ css::java::XJavaThreadRegister_11, css::container::XContainerListener>
+{
+public:
+ explicit JavaVirtualMachine(
+ css::uno::Reference<
+ css::uno::XComponentContext > const & rContext);
+
+ // XInitialization
+ virtual void SAL_CALL
+ initialize(css::uno::Sequence< css::uno::Any > const &
+ rArguments) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService(OUString const & rServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XJavaVM
+ virtual css::uno::Any SAL_CALL
+ getJavaVM(css::uno::Sequence< sal_Int8 > const & rProcessId) override;
+
+ virtual sal_Bool SAL_CALL isVMStarted() override;
+
+ virtual sal_Bool SAL_CALL isVMEnabled() override;
+
+ // XJavaThreadRegister_11
+ virtual sal_Bool SAL_CALL isThreadAttached() override;
+
+ virtual void SAL_CALL registerThread() override;
+
+ virtual void SAL_CALL revokeThread() override;
+
+ // XContainerListener
+ virtual void SAL_CALL
+ disposing(css::lang::EventObject const & rSource) override;
+
+ virtual void SAL_CALL
+ elementInserted(css::container::ContainerEvent const & rEvent) override;
+
+ virtual void SAL_CALL
+ elementRemoved(css::container::ContainerEvent const & rEvent) override;
+
+ virtual void SAL_CALL
+ elementReplaced(css::container::ContainerEvent const & rEvent) override;
+
+private:
+ JavaVirtualMachine(JavaVirtualMachine const &) = delete;
+ void operator =(const JavaVirtualMachine&) = delete;
+
+ virtual ~JavaVirtualMachine() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ void registerConfigChangesListener();
+
+ void setINetSettingsInVM(bool set_reset);
+
+ void setUpUnoVirtualMachine(JNIEnv * environment);
+
+ void handleJniException(JNIEnv * environment);
+
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+
+ // the following are controlled by BaseMutex::m_aMutex:
+ bool m_bDisposed;
+ rtl::Reference< jvmaccess::VirtualMachine > m_xVirtualMachine;
+ rtl::Reference< jvmaccess::UnoVirtualMachine > m_xUnoVirtualMachine;
+ JavaVM * m_pJavaVm;
+ // If the first creation of Java failed and this flag is set then the
+ // next call to getJavaVM throws a RuntimException. This is useful when
+ // the second attempt to create Java might cause a crash.
+ css::uno::Reference< css::container::XContainer >
+ m_xInetConfiguration;
+ css::uno::Reference< css::container::XContainer >
+ m_xJavaConfiguration; // for Java settings
+
+ osl::ThreadData m_aAttachGuards;
+};
+
+}
+
+#endif // INCLUDED_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/jvmargs.cxx b/stoc/source/javavm/jvmargs.cxx
new file mode 100644
index 000000000..f98f22ec0
--- /dev/null
+++ b/stoc/source/javavm/jvmargs.cxx
@@ -0,0 +1,32 @@
+/* -*- 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 "jvmargs.hxx"
+#include <rtl/ustring.hxx>
+
+namespace stoc_javavm
+{
+JVM::JVM() noexcept //: _enabled(sal_False)
+{
+}
+
+void JVM::pushProp(const OUString& property) { _props.push_back(property); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/jvmargs.hxx b/stoc/source/javavm/jvmargs.hxx
new file mode 100644
index 000000000..adc41ffa1
--- /dev/null
+++ b/stoc/source/javavm/jvmargs.hxx
@@ -0,0 +1,58 @@
+/* -*- 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 .
+ */
+
+
+#ifndef INCLUDED_STOC_SOURCE_JAVAVM_JVMARGS_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_JVMARGS_HXX
+
+
+#include <vector>
+#include <rtl/ustring.hxx>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+extern "C" {
+ typedef jint JNICALL JNI_InitArgs_Type(void *);
+ typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
+
+}
+
+namespace stoc_javavm {
+
+ class JVM {
+ ::std::vector<OUString> _props;
+
+ public:
+ JVM() noexcept;
+
+ void pushProp(const OUString & uString);
+ const ::std::vector< OUString> & getProperties() const { return _props;}
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/loader/dllcomponentloader.cxx b/stoc/source/loader/dllcomponentloader.cxx
new file mode 100644
index 000000000..43f20ad0a
--- /dev/null
+++ b/stoc/source/loader/dllcomponentloader.cxx
@@ -0,0 +1,152 @@
+/* -*- 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 <rtl/ustring.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/shlib.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace com::sun::star::registry { class XRegistryKey; }
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::loader;
+using namespace css::lang;
+using namespace css::registry;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+class DllComponentLoader
+ : public WeakImplHelper< XImplementationLoader,
+ XInitialization,
+ XServiceInfo >
+{
+public:
+ explicit DllComponentLoader( const Reference<XComponentContext> & xCtx );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XImplementationLoader
+ virtual Reference<XInterface> SAL_CALL activate( const OUString& implementationName, const OUString& implementationLoaderUrl, const OUString& locationUrl, const Reference<XRegistryKey>& xKey ) override;
+ virtual sal_Bool SAL_CALL writeRegistryInfo( const Reference<XRegistryKey>& xKey, const OUString& implementationLoaderUrl, const OUString& locationUrl ) override;
+
+private:
+ Reference<XMultiServiceFactory> m_xSMgr;
+};
+
+
+DllComponentLoader::DllComponentLoader( const Reference<XComponentContext> & xCtx )
+{
+ m_xSMgr.set( xCtx->getServiceManager(), UNO_QUERY );
+}
+
+OUString SAL_CALL DllComponentLoader::getImplementationName( )
+{
+ return "com.sun.star.comp.stoc.DLLComponentLoader";
+}
+
+sal_Bool SAL_CALL DllComponentLoader::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL DllComponentLoader::getSupportedServiceNames( )
+{
+ return { "com.sun.star.loader.SharedLibrary" };
+}
+
+
+void DllComponentLoader::initialize( const css::uno::Sequence< css::uno::Any >& )
+{
+ OSL_FAIL( "dllcomponentloader::initialize should not be called !" );
+// if( aArgs.getLength() != 1 )
+// {
+// throw IllegalArgumentException();
+// }
+
+// Reference< XMultiServiceFactory > rServiceManager;
+
+// if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE )
+// {
+// aArgs.getConstArray()[0] >>= rServiceManager;
+// }
+
+// if( !rServiceManager.is() )
+// {
+// throw IllegalArgumentException();
+// }
+
+// m_xSMgr = rServiceManager;
+}
+
+
+Reference<XInterface> SAL_CALL DllComponentLoader::activate(
+ const OUString & rImplName, const OUString &, const OUString & rLibName,
+ const Reference< XRegistryKey > & )
+{
+ return loadSharedLibComponentFactory(
+ cppu::bootstrap_expandUri(rLibName), OUString(), rImplName, m_xSMgr,
+ css::uno::Reference<css::registry::XRegistryKey>());
+}
+
+
+sal_Bool SAL_CALL DllComponentLoader::writeRegistryInfo(
+ const Reference< XRegistryKey > & xKey, const OUString &, const OUString & rLibName )
+{
+#ifdef DISABLE_DYNLOADING
+ (void) xKey;
+ (void) rLibName;
+ OSL_FAIL( "DllComponentLoader::writeRegistryInfo() should not be called I think?" );
+ return sal_False;
+#else
+ writeSharedLibComponentInfo(
+ cppu::bootstrap_expandUri(rLibName), OUString(), m_xSMgr, xKey );
+ return true;
+#endif
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_DLLComponentLoader_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new DllComponentLoader(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/namingservice/namingservice.component b/stoc/source/namingservice/namingservice.component
new file mode 100644
index 000000000..3ba192e86
--- /dev/null
+++ b/stoc/source/namingservice/namingservice.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.NamingService"
+ constructor="stoc_NamingService_Impl_get_implementation">
+ <service name="com.sun.star.uno.NamingService"/>
+ </implementation>
+</component>
diff --git a/stoc/source/namingservice/namingservice.cxx b/stoc/source/namingservice/namingservice.cxx
new file mode 100644
index 000000000..acabb7370
--- /dev/null
+++ b/stoc/source/namingservice/namingservice.cxx
@@ -0,0 +1,123 @@
+/* -*- 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/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/uno/XNamingService.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <mutex>
+#include <unordered_map>
+
+using namespace cppu;
+using namespace osl;
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::registry;
+
+
+namespace stoc_namingservice
+{
+
+typedef std::unordered_map< OUString, Reference<XInterface > > HashMap_OWString_Interface;
+
+namespace {
+
+class NamingService_Impl
+ : public WeakImplHelper < XServiceInfo, XNamingService >
+{
+ std::mutex aMutex;
+ HashMap_OWString_Interface aMap;
+public:
+ NamingService_Impl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+};
+
+}
+
+
+
+NamingService_Impl::NamingService_Impl() {}
+
+// XServiceInfo
+OUString NamingService_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.NamingService";
+}
+
+// XServiceInfo
+sal_Bool NamingService_Impl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > NamingService_Impl::getSupportedServiceNames()
+{
+ return { "com.sun.star.uno.NamingService" };
+}
+
+// XServiceInfo
+Reference< XInterface > NamingService_Impl::getRegisteredObject( const OUString& Name )
+{
+ std::scoped_lock aGuard( aMutex );
+ Reference< XInterface > xRet;
+ HashMap_OWString_Interface::iterator aIt = aMap.find( Name );
+ if( aIt != aMap.end() )
+ xRet = (*aIt).second;
+ return xRet;
+}
+
+// XServiceInfo
+void NamingService_Impl::registerObject( const OUString& Name, const Reference< XInterface >& Object )
+{
+ std::scoped_lock aGuard( aMutex );
+ aMap[ Name ] = Object;
+}
+
+// XServiceInfo
+void NamingService_Impl::revokeObject( const OUString& Name )
+{
+ std::scoped_lock aGuard( aMutex );
+ aMap.erase( Name );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_NamingService_Impl_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new stoc_namingservice::NamingService_Impl());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/proxy_factory/proxyfac.component b/stoc/source/proxy_factory/proxyfac.component
new file mode 100644
index 000000000..b069f88df
--- /dev/null
+++ b/stoc/source/proxy_factory/proxyfac.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.reflection.ProxyFactory"
+ constructor="stoc_FactoryImpl_get_implementation" single-instance="true">
+ <service name="com.sun.star.reflection.ProxyFactory"/>
+ </implementation>
+</component>
diff --git a/stoc/source/proxy_factory/proxyfac.cxx b/stoc/source/proxy_factory/proxyfac.cxx
new file mode 100644
index 000000000..107d37160
--- /dev/null
+++ b/stoc/source/proxy_factory/proxyfac.cxx
@@ -0,0 +1,410 @@
+/* -*- 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 <rtl/ref.hxx>
+#include <uno/dispatcher.hxx>
+#include <uno/data.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+#include <uno/environment.hxx>
+#include <typelib/typedescription.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+
+namespace
+{
+
+struct FactoryImpl : public ::cppu::WeakImplHelper< lang::XServiceInfo,
+ reflection::XProxyFactory >
+{
+ Environment m_uno_env;
+ Environment m_cpp_env;
+ Mapping m_uno2cpp;
+ Mapping m_cpp2uno;
+
+ UnoInterfaceReference binuno_queryInterface(
+ UnoInterfaceReference const & unoI,
+ typelib_InterfaceTypeDescription * pTypeDescr );
+
+ FactoryImpl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XProxyFactory
+ virtual Reference< XAggregation > SAL_CALL createProxy(
+ Reference< XInterface > const & xTarget ) override;
+};
+
+
+UnoInterfaceReference FactoryImpl::binuno_queryInterface(
+ UnoInterfaceReference const & unoI,
+ typelib_InterfaceTypeDescription * pTypeDescr )
+{
+ // init queryInterface() td
+ static typelib_TypeDescription* s_pQITD = []() {
+ typelib_TypeDescription* pTXInterfaceDescr = nullptr;
+ TYPELIB_DANGER_GET(&pTXInterfaceDescr, cppu::UnoType<XInterface>::get().getTypeLibType());
+ typelib_TypeDescription* pQITD = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ &pQITD, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTXInterfaceDescr)
+ ->ppAllMembers[0]);
+ TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
+ return pQITD;
+ }();
+
+ void * args[ 1 ];
+ args[ 0 ] = &reinterpret_cast< typelib_TypeDescription * >(
+ pTypeDescr )->pWeakRef;
+ uno_Any ret_val, exc_space;
+ uno_Any * exc = &exc_space;
+
+ unoI.dispatch( s_pQITD, &ret_val, args, &exc );
+
+ if (exc == nullptr)
+ {
+ UnoInterfaceReference ret;
+ if (ret_val.pType->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ ret.set( *static_cast< uno_Interface ** >(ret_val.pData),
+ SAL_NO_ACQUIRE );
+ typelib_typedescriptionreference_release( ret_val.pType );
+ }
+ else
+ {
+ uno_any_destruct( &ret_val, nullptr );
+ }
+ return ret;
+ }
+ else
+ {
+ // exception occurred:
+ OSL_ENSURE(
+ typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType<RuntimeException>::get().getTypeLibType(),
+ exc->pType ),
+ "### RuntimeException expected!" );
+ Any cpp_exc;
+ uno_type_copyAndConvertData(
+ &cpp_exc, exc, cppu::UnoType<decltype(cpp_exc)>::get().getTypeLibType(),
+ m_uno2cpp.get() );
+ uno_any_destruct( exc, nullptr );
+ ::cppu::throwException( cpp_exc );
+ OSL_ASSERT( false ); // way of no return
+ return UnoInterfaceReference(); // for dummy
+ }
+}
+
+
+struct ProxyRoot : public ::cppu::OWeakAggObject
+{
+ // XAggregation
+ virtual Any SAL_CALL queryAggregation( Type const & rType ) override;
+
+ ProxyRoot( ::rtl::Reference< FactoryImpl > const & factory,
+ Reference< XInterface > const & xTarget );
+
+ ::rtl::Reference< FactoryImpl > m_factory;
+
+private:
+ UnoInterfaceReference m_target;
+};
+
+
+struct binuno_Proxy : public uno_Interface
+{
+ oslInterlockedCount m_nRefCount;
+ ::rtl::Reference< ProxyRoot > m_root;
+ UnoInterfaceReference m_target;
+ OUString m_oid;
+ TypeDescription m_typeDescr;
+
+ binuno_Proxy(
+ ::rtl::Reference< ProxyRoot > const & root,
+ UnoInterfaceReference const & target,
+ OUString const & oid, TypeDescription const & typeDescr );
+};
+
+extern "C"
+{
+
+
+static void binuno_proxy_free(
+ uno_ExtEnvironment * pEnv, void * pProxy )
+{
+ binuno_Proxy * proxy = static_cast< binuno_Proxy * >(
+ static_cast< uno_Interface * >( pProxy ) );
+ OSL_ASSERT( proxy->m_root->m_factory->m_uno_env.get()->pExtEnv == pEnv );
+ delete proxy;
+}
+
+
+static void binuno_proxy_acquire( uno_Interface * pUnoI )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ if (osl_atomic_increment( &that->m_nRefCount ) != 1)
+ return;
+
+ // rebirth of zombie
+ uno_ExtEnvironment * uno_env =
+ that->m_root->m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->registerProxyInterface)(
+ uno_env, reinterpret_cast< void ** >( &pUnoI ), binuno_proxy_free,
+ that->m_oid.pData,
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ that->m_typeDescr.get() ) );
+ OSL_ASSERT( that == static_cast< binuno_Proxy * >( pUnoI ) );
+}
+
+
+static void binuno_proxy_release( uno_Interface * pUnoI )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ if (osl_atomic_decrement( &that->m_nRefCount ) == 0)
+ {
+ uno_ExtEnvironment * uno_env =
+ that->m_root->m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->revokeInterface)( uno_env, pUnoI );
+ }
+}
+
+
+static void binuno_proxy_dispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType,
+ void * pReturn, void * pArgs [], uno_Any ** ppException )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription const * >(
+ pMemberType )->nPosition)
+ {
+ case 0: // queryInterface()
+ {
+ try
+ {
+ Type const & rType =
+ *static_cast< Type const * >( pArgs[ 0 ] );
+ Any ret( that->m_root->queryInterface( rType ) );
+ uno_type_copyAndConvertData(
+ pReturn, &ret, cppu::UnoType<decltype(ret)>::get().getTypeLibType(),
+ that->m_root->m_factory->m_cpp2uno.get() );
+ *ppException = nullptr; // no exc
+ }
+ catch (RuntimeException &)
+ {
+ Any exc( ::cppu::getCaughtException() );
+ uno_type_any_constructAndConvert(
+ *ppException, const_cast< void * >(exc.getValue()),
+ exc.getValueTypeRef(),
+ that->m_root->m_factory->m_cpp2uno.get() );
+ }
+ break;
+ }
+ case 1: // acquire()
+ binuno_proxy_acquire( pUnoI );
+ *ppException = nullptr; // no exc
+ break;
+ case 2: // release()
+ binuno_proxy_release( pUnoI );
+ *ppException = nullptr; // no exc
+ break;
+ default:
+ that->m_target.dispatch( pMemberType, pReturn, pArgs, ppException );
+ break;
+ }
+}
+
+}
+
+
+binuno_Proxy::binuno_Proxy(
+ ::rtl::Reference< ProxyRoot > const & root,
+ UnoInterfaceReference const & target,
+ OUString const & oid, TypeDescription const & typeDescr )
+ : m_nRefCount( 1 ),
+ m_root( root ),
+ m_target( target ),
+ m_oid( oid ),
+ m_typeDescr( typeDescr )
+{
+ uno_Interface::acquire = binuno_proxy_acquire;
+ uno_Interface::release = binuno_proxy_release;
+ uno_Interface::pDispatcher = binuno_proxy_dispatch;
+}
+
+ProxyRoot::ProxyRoot(
+ ::rtl::Reference< FactoryImpl > const & factory,
+ Reference< XInterface > const & xTarget )
+ : m_factory( factory )
+{
+ m_factory->m_cpp2uno.mapInterface(
+ reinterpret_cast< void ** >( &m_target.m_pUnoI ), xTarget.get(),
+ cppu::UnoType<decltype(xTarget)>::get() );
+ OSL_ENSURE( m_target.is(), "### mapping interface failed!" );
+}
+
+
+Any ProxyRoot::queryAggregation( Type const & rType )
+{
+ Any ret( OWeakAggObject::queryAggregation( rType ) );
+ if (! ret.hasValue())
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, rType.getTypeLibType() );
+ try
+ {
+ Reference< XInterface > xProxy;
+ uno_ExtEnvironment * cpp_env = m_factory->m_cpp_env.get()->pExtEnv;
+ OSL_ASSERT( cpp_env != nullptr );
+
+ // mind a new delegator, calculate current root:
+ Reference< XInterface > xRoot(
+ static_cast< OWeakObject * >(this), UNO_QUERY_THROW );
+ OUString oid;
+ (*cpp_env->getObjectIdentifier)( cpp_env, &oid.pData, xRoot.get() );
+ OSL_ASSERT( !oid.isEmpty() );
+
+ (*cpp_env->getRegisteredInterface)(
+ cpp_env, reinterpret_cast< void ** >( &xProxy ),
+ oid.pData, reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(pTypeDescr) );
+ if (! xProxy.is())
+ {
+ // perform query on target:
+ UnoInterfaceReference proxy_target(
+ m_factory->binuno_queryInterface(
+ m_target, reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(pTypeDescr) ) );
+ if (proxy_target.is())
+ {
+ // ensure root's object entries:
+ UnoInterfaceReference root;
+ m_factory->m_cpp2uno.mapInterface(
+ reinterpret_cast< void ** >( &root.m_pUnoI ),
+ xRoot.get(), cppu::UnoType<decltype(xRoot)>::get() );
+
+ UnoInterfaceReference proxy(
+ // ref count initially 1:
+ new binuno_Proxy( this, proxy_target, oid, pTypeDescr ),
+ SAL_NO_ACQUIRE );
+ uno_ExtEnvironment * uno_env =
+ m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->registerProxyInterface)(
+ uno_env, reinterpret_cast< void ** >( &proxy.m_pUnoI ),
+ binuno_proxy_free, oid.pData,
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ pTypeDescr ) );
+
+ m_factory->m_uno2cpp.mapInterface(
+ reinterpret_cast< void ** >( &xProxy ),
+ proxy.get(), pTypeDescr );
+ }
+ }
+ if (xProxy.is())
+ ret.setValue( &xProxy, pTypeDescr );
+ }
+ catch (...) // finally
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ throw;
+ }
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ return ret;
+}
+
+
+FactoryImpl::FactoryImpl()
+{
+ OUString uno = UNO_LB_UNO;
+ OUString cpp = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+
+ uno_getEnvironment(
+ reinterpret_cast< uno_Environment ** >( &m_uno_env ), uno.pData, nullptr );
+ OSL_ENSURE( m_uno_env.is(), "### cannot get binary uno env!" );
+
+ uno_getEnvironment(
+ reinterpret_cast< uno_Environment ** >( &m_cpp_env ), cpp.pData, nullptr );
+ OSL_ENSURE( m_cpp_env.is(), "### cannot get C++ uno env!" );
+
+ uno_getMapping(
+ reinterpret_cast< uno_Mapping ** >( &m_uno2cpp ),
+ m_uno_env.get(), m_cpp_env.get(), nullptr );
+ OSL_ENSURE( m_uno2cpp.is(), "### cannot get bridge uno <-> C++!" );
+
+ uno_getMapping(
+ reinterpret_cast< uno_Mapping ** >( &m_cpp2uno ),
+ m_cpp_env.get(), m_uno_env.get(), nullptr );
+ OSL_ENSURE( m_cpp2uno.is(), "### cannot get bridge C++ <-> uno!" );
+}
+
+// XProxyFactory
+
+Reference< XAggregation > FactoryImpl::createProxy(
+ Reference< XInterface > const & xTarget )
+{
+ return new ProxyRoot( this, xTarget );
+}
+
+// XServiceInfo
+
+OUString FactoryImpl::getImplementationName()
+{
+ return "com.sun.star.comp.reflection.ProxyFactory";
+}
+
+sal_Bool FactoryImpl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > FactoryImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.reflection.ProxyFactory" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_FactoryImpl_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new FactoryImpl);
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/access_controller.cxx b/stoc/source/security/access_controller.cxx
new file mode 100644
index 000000000..c96f1f61f
--- /dev/null
+++ b/stoc/source/security/access_controller.cxx
@@ -0,0 +1,863 @@
+/* -*- 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 <vector>
+
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <uno/current_context.h>
+#include <uno/lbnames.h>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/security/XAccessController.hpp>
+#include <com/sun/star/security/XPolicy.hpp>
+
+#include "lru_cache.h"
+#include "permissions.h"
+
+#include <memory>
+
+constexpr OUStringLiteral SERVICE_NAME = u"com.sun.star.security.AccessController";
+constexpr OUStringLiteral USER_CREDS = u"access-control.user-credentials.id";
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace stoc_sec;
+
+namespace {
+
+// static stuff initialized when loading lib
+OUString s_envType = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+constexpr OUStringLiteral s_acRestriction = u"access-control.restriction";
+
+
+/** ac context intersects permissions of two ac contexts
+*/
+class acc_Intersection
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+public:
+ static Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+acc_Intersection::acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{}
+
+Reference< security::XAccessControlContext > acc_Intersection::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+{
+ if (! x1.is())
+ return x2;
+ if (! x2.is())
+ return x1;
+ return new acc_Intersection( x1, x2 );
+}
+
+void acc_Intersection::checkPermission(
+ Any const & perm )
+{
+ m_x1->checkPermission( perm );
+ m_x2->checkPermission( perm );
+}
+
+/** ac context unifies permissions of two ac contexts
+*/
+class acc_Union
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+public:
+ static Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+acc_Union::acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{}
+
+Reference< security::XAccessControlContext > acc_Union::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+{
+ if (! x1.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ if (! x2.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ return new acc_Union( x1, x2 );
+}
+
+void acc_Union::checkPermission(
+ Any const & perm )
+{
+ try
+ {
+ m_x1->checkPermission( perm );
+ }
+ catch (security::AccessControlException &)
+ {
+ m_x2->checkPermission( perm );
+ }
+}
+
+/** ac context doing permission checks on static permissions
+*/
+class acc_Policy
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ PermissionCollection m_permissions;
+
+public:
+ explicit acc_Policy(
+ PermissionCollection const & permissions )
+ : m_permissions( permissions )
+ {}
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+void acc_Policy::checkPermission(
+ Any const & perm )
+{
+ m_permissions.checkPermission( perm );
+}
+
+/** current context overriding dynamic ac restriction
+*/
+class acc_CurrentContext
+ : public WeakImplHelper< XCurrentContext >
+{
+ Reference< XCurrentContext > m_xDelegate;
+ Any m_restriction;
+
+public:
+ acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction );
+
+ // XCurrentContext impl
+ virtual Any SAL_CALL getValueByName( OUString const & name ) override;
+};
+
+acc_CurrentContext::acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ : m_xDelegate( xDelegate )
+{
+ if (xRestriction.is())
+ {
+ m_restriction <<= xRestriction;
+ }
+ // return empty any otherwise on getValueByName(), not null interface
+}
+
+Any acc_CurrentContext::getValueByName( OUString const & name )
+{
+ if (name == s_acRestriction)
+ {
+ return m_restriction;
+ }
+ else if (m_xDelegate.is())
+ {
+ return m_xDelegate->getValueByName( name );
+ }
+ else
+ {
+ return Any();
+ }
+}
+
+
+Reference< security::XAccessControlContext > getDynamicRestriction(
+ Reference< XCurrentContext > const & xContext )
+{
+ if (xContext.is())
+ {
+ Any acc(xContext->getValueByName(s_acRestriction));
+ if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
+ {
+ // avoid ref-counting
+ OUString const & typeName =
+ OUString::unacquired( &acc.pType->pTypeName );
+ if ( typeName == "com.sun.star.security.XAccessControlContext" )
+ {
+ return Reference< security::XAccessControlContext >(
+ *static_cast< security::XAccessControlContext ** >( acc.pData ) );
+ }
+ else // try to query
+ {
+ return Reference< security::XAccessControlContext >::query(
+ *static_cast< XInterface ** >( acc.pData ) );
+ }
+ }
+ }
+ return Reference< security::XAccessControlContext >();
+}
+
+class cc_reset
+{
+ void * m_cc;
+public:
+ explicit cc_reset( void * cc )
+ : m_cc( cc ) {}
+ ~cc_reset()
+ { ::uno_setCurrentContext( m_cc, s_envType.pData, nullptr ); }
+};
+
+typedef WeakComponentImplHelper<
+ security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;
+
+
+class AccessController
+ : public cppu::BaseMutex
+ , public t_helper
+{
+ Reference< XComponentContext > m_xComponentContext;
+
+ Reference< security::XPolicy > m_xPolicy;
+ Reference< security::XPolicy > const & getPolicy();
+
+ // mode
+ enum class Mode { Off, On, DynamicOnly, SingleUser, SingleDefaultUser };
+ Mode m_mode;
+
+ PermissionCollection m_defaultPermissions;
+ // for single-user mode
+ PermissionCollection m_singleUserPermissions;
+ OUString m_singleUserId;
+ bool m_defaultPerm_init;
+ bool m_singleUser_init;
+ // for multi-user mode
+ lru_cache< OUString, PermissionCollection, OUStringHash, equal_to< OUString > >
+ m_user2permissions;
+
+ ThreadData m_rec;
+ typedef vector< pair< OUString, Any > > t_rec_vec;
+ void clearPostPoned();
+ void checkAndClearPostPoned();
+
+ PermissionCollection getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm );
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit AccessController( Reference< XComponentContext > const & xComponentContext );
+
+ // XInitialization impl
+ virtual void SAL_CALL initialize(
+ Sequence< Any > const & arguments ) override;
+
+ // XAccessController impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+ virtual Any SAL_CALL doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction ) override;
+ virtual Any SAL_CALL doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction ) override;
+ virtual Reference< security::XAccessControlContext > SAL_CALL getContext() override;
+
+ // XServiceInfo impl
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
+ : t_helper( m_aMutex )
+ , m_xComponentContext( xComponentContext )
+ , m_mode( Mode::On ) // default
+ , m_defaultPerm_init( false )
+ , m_singleUser_init( false )
+ , m_rec( nullptr )
+{
+ // The .../mode value had originally been set in
+ // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
+ // to something other than "off" depending on various UNO_AC* bootstrap
+ // variables that are no longer supported, so this is mostly dead code now:
+ OUString mode;
+ if (m_xComponentContext->getValueByName( "/services/" + SERVICE_NAME + "/mode" ) >>= mode)
+ {
+ if ( mode == "off" )
+ {
+ m_mode = Mode::Off;
+ }
+ else if ( mode == "on" )
+ {
+ m_mode = Mode::On;
+ }
+ else if ( mode == "dynamic-only" )
+ {
+ m_mode = Mode::DynamicOnly;
+ }
+ else if ( mode == "single-user" )
+ {
+ m_xComponentContext->getValueByName(
+ "/services/" + SERVICE_NAME + "/single-user-id" ) >>= m_singleUserId;
+ if (m_singleUserId.isEmpty())
+ {
+ throw RuntimeException(
+ "expected a user id in component context entry "
+ "\"/services/" + SERVICE_NAME + "/single-user-id\"!",
+ static_cast<OWeakObject *>(this) );
+ }
+ m_mode = Mode::SingleUser;
+ }
+ else if ( mode == "single-default-user" )
+ {
+ m_mode = Mode::SingleDefaultUser;
+ }
+ }
+
+ // switch on caching for Mode::DynamicOnly and Mode::On (shareable multi-user process)
+ if (Mode::On != m_mode && Mode::DynamicOnly != m_mode)
+ return;
+
+ sal_Int32 cacheSize = 0; // multi-user cache size
+ if (! (m_xComponentContext->getValueByName(
+ "/services/" + SERVICE_NAME + "/user-cache-size" ) >>= cacheSize))
+ {
+ cacheSize = 128; // reasonable default?
+ }
+#ifdef __CACHE_DIAGNOSE
+ cacheSize = 2;
+#endif
+ m_user2permissions.setSize( cacheSize );
+}
+
+void AccessController::disposing()
+{
+ m_mode = Mode::Off; // avoid checks from now on xxx todo review/ better Mode::DynamicOnly?
+ m_xPolicy.clear();
+ m_xComponentContext.clear();
+}
+
+// XInitialization impl
+
+void AccessController::initialize(
+ Sequence< Any > const & arguments )
+{
+ // xxx todo: review for forking
+ // portal forking hack: re-initialize for another user-id
+ if (Mode::SingleUser != m_mode) // only if in single-user mode
+ {
+ throw RuntimeException(
+ "invalid call: ac must be in \"single-user\" mode!", static_cast<OWeakObject *>(this) );
+ }
+ OUString userId;
+ arguments[ 0 ] >>= userId;
+ if ( userId.isEmpty() )
+ {
+ throw RuntimeException(
+ "expected a user-id as first argument!", static_cast<OWeakObject *>(this) );
+ }
+ // assured that no sync is necessary: no check happens at this forking time
+ m_singleUserId = userId;
+ m_singleUser_init = false;
+}
+
+
+Reference< security::XPolicy > const & AccessController::getPolicy()
+{
+ // get policy singleton
+ if (! m_xPolicy.is())
+ {
+ Reference< security::XPolicy > xPolicy;
+ m_xComponentContext->getValueByName(
+ "/singletons/com.sun.star.security.thePolicy" ) >>= xPolicy;
+ if (!xPolicy.is())
+ {
+ throw SecurityException(
+ "cannot get policy singleton!", static_cast<OWeakObject *>(this) );
+ }
+
+ MutexGuard guard( m_aMutex );
+ if (! m_xPolicy.is())
+ {
+ m_xPolicy = xPolicy;
+ }
+ }
+ return m_xPolicy;
+}
+
+#ifdef __DIAGNOSE
+static void dumpPermissions(
+ PermissionCollection const & collection, OUString const & userId = OUString() )
+{
+ OUStringBuffer buf( 48 );
+ if (!userId.isEmpty())
+ {
+ buf.append( "> dumping permissions of user \"" );
+ buf.append( userId );
+ buf.append( "\":" );
+ }
+ else
+ {
+ buf.append( "> dumping default permissions:" );
+ }
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+ Sequence< OUString > permissions( collection.toStrings() );
+ OUString const * p = permissions.getConstArray();
+ for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
+ {
+ SAL_INFO("stoc", p[ nPos ] );
+ }
+ SAL_INFO("stoc", "> permission dump done" );
+}
+#endif
+
+
+void AccessController::clearPostPoned()
+{
+ delete static_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( nullptr );
+}
+
+void AccessController::checkAndClearPostPoned()
+{
+ // check postponed permissions
+ std::unique_ptr< t_rec_vec > rec( static_cast< t_rec_vec * >( m_rec.getData() ) );
+ m_rec.setData( nullptr ); // takeover ownership
+ OSL_ASSERT(rec);
+ if (!rec)
+ return;
+
+ t_rec_vec const& vec = *rec;
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ OSL_ASSERT( m_singleUser_init );
+ for (const auto & p : vec)
+ {
+ OSL_ASSERT( m_singleUserId == p.first );
+ m_singleUserPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ OSL_ASSERT( m_defaultPerm_init );
+ for (const auto & p : vec)
+ {
+ OSL_ASSERT( p.first.isEmpty() ); // default-user
+ m_defaultPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case Mode::On:
+ {
+ for (const auto & p : vec)
+ {
+ PermissionCollection const * pPermissions;
+ // lookup policy for user
+ {
+ MutexGuard guard( m_aMutex );
+ pPermissions = m_user2permissions.lookup( p.first );
+ }
+ OSL_ASSERT( pPermissions );
+ if (pPermissions)
+ {
+ pPermissions->checkPermission( p.second );
+ }
+ }
+ break;
+ }
+ default:
+ OSL_FAIL( "### this should never be called in this ac mode!" );
+ break;
+ }
+}
+
+/** this is the only function calling the policy singleton and thus has to take care
+ of recurring calls!
+
+ @param demanded_perm (if not empty) is the demanded permission of a checkPermission() call
+ which will be postponed for recurring calls
+*/
+PermissionCollection AccessController::getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm )
+{
+ OUString userId;
+
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ if (m_singleUser_init)
+ return m_singleUserPermissions;
+ userId = m_singleUserId;
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ if (m_defaultPerm_init)
+ return m_defaultPermissions;
+ break;
+ }
+ case Mode::On:
+ {
+ if (xContext.is())
+ {
+ xContext->getValueByName( USER_CREDS ) >>= userId;
+ }
+ if ( userId.isEmpty() )
+ {
+ throw SecurityException(
+ "cannot determine current user in multi-user ac!", static_cast<OWeakObject *>(this) );
+ }
+
+ // lookup policy for user
+ MutexGuard guard( m_aMutex );
+ PermissionCollection const * pPermissions = m_user2permissions.lookup( userId );
+ if (pPermissions)
+ return *pPermissions;
+ break;
+ }
+ default:
+ OSL_FAIL( "### this should never be called in this ac mode!" );
+ return PermissionCollection();
+ }
+
+ // call on policy
+ // iff this is a recurring call for the default user, then grant all permissions
+ t_rec_vec * rec = static_cast< t_rec_vec * >( m_rec.getData() );
+ if (rec) // tls entry exists => this is recursive call
+ {
+ if (demanded_perm.hasValue())
+ {
+ // enqueue
+ rec->push_back( pair< OUString, Any >( userId, demanded_perm ) );
+ }
+#ifdef __DIAGNOSE
+ SAL_INFO("stoc", "> info: recurring call of user: " << userId );
+#endif
+ return PermissionCollection( new AllPermission() );
+ }
+ else // no tls
+ {
+ rec = new t_rec_vec;
+ m_rec.setData( rec );
+ }
+
+ try // calls on API
+ {
+ // init default permissions
+ if (! m_defaultPerm_init)
+ {
+ PermissionCollection defaultPermissions(
+ getPolicy()->getDefaultPermissions() );
+ // assign
+ MutexGuard guard( m_aMutex );
+ if (! m_defaultPerm_init)
+ {
+ m_defaultPermissions = defaultPermissions;
+ m_defaultPerm_init = true;
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( m_defaultPermissions );
+#endif
+ }
+
+ PermissionCollection ret;
+
+ // init user permissions
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // assign
+ MutexGuard guard( m_aMutex );
+ if (m_singleUser_init)
+ {
+ ret = m_singleUserPermissions;
+ }
+ else
+ {
+ m_singleUserPermissions = ret;
+ m_singleUser_init = true;
+ }
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ ret = m_defaultPermissions;
+ break;
+ }
+ case Mode::On:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // cache
+ MutexGuard guard( m_aMutex );
+ m_user2permissions.set( userId, ret );
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+
+ // check postponed
+ checkAndClearPostPoned();
+ return ret;
+ }
+ catch (const security::AccessControlException & exc) // wrapped into DeploymentException
+ {
+ clearPostPoned(); // safety: exception could have happened before checking postponed?
+ throw DeploymentException( "deployment error (AccessControlException occurred): " + exc.Message, exc.Context );
+ }
+ catch (RuntimeException &)
+ {
+ // don't check postponed, just cleanup
+ clearPostPoned();
+ delete static_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( nullptr );
+ throw;
+ }
+ catch (Exception &)
+ {
+ // check postponed permissions first
+ // => AccessControlExceptions are errors, user exceptions not!
+ checkAndClearPostPoned();
+ throw;
+ }
+ catch (...)
+ {
+ // don't check postponed, just cleanup
+ clearPostPoned();
+ throw;
+ }
+}
+
+// XAccessController impl
+
+void AccessController::checkPermission(
+ Any const & perm )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "checkPermission() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
+ }
+
+ if (Mode::Off == m_mode)
+ return;
+
+ // first dynamic check of ac contexts
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+ Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
+ if (xACC.is())
+ {
+ xACC->checkPermission( perm );
+ }
+
+ if (Mode::DynamicOnly == m_mode)
+ return;
+
+ // then static check
+ getEffectivePermissions( xContext, perm ).checkPermission( perm );
+}
+
+Any AccessController::doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "doRestricted() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
+ }
+
+ if (Mode::Off == m_mode) // optimize this way, because no dynamic check will be performed
+ return xAction->run();
+
+ if (xRestriction.is())
+ {
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Intersection::create(
+ xRestriction, getDynamicRestriction( xContext ) ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else
+ {
+ return xAction->run();
+ }
+}
+
+Any AccessController::doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "doPrivileged() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
+ }
+
+ if (Mode::Off == m_mode) // no dynamic check will be performed
+ {
+ return xAction->run();
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ Reference< security::XAccessControlContext > xOldRestr(
+ getDynamicRestriction( xContext ) );
+
+ if (xOldRestr.is()) // previous restriction
+ {
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Union::create( xRestriction, xOldRestr ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else // no previous restriction => never current restriction
+ {
+ return xAction->run();
+ }
+}
+
+Reference< security::XAccessControlContext > AccessController::getContext()
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "getContext() call on disposed AccessController!", static_cast<OWeakObject *>(this) );
+ }
+
+ if (Mode::Off == m_mode) // optimize this way, because no dynamic check will be performed
+ {
+ return new acc_Policy( PermissionCollection( new AllPermission() ) );
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ return acc_Intersection::create(
+ getDynamicRestriction( xContext ),
+ new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
+}
+
+// XServiceInfo impl
+
+OUString AccessController::getImplementationName()
+{
+ return "com.sun.star.security.comp.stoc.AccessController";
+}
+
+sal_Bool AccessController::supportsService( OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+Sequence< OUString > AccessController::getSupportedServiceNames()
+{
+ Sequence<OUString> aSNS { SERVICE_NAME };
+ return aSNS;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_security_comp_stoc_AccessController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new AccessController(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/file_policy.cxx b/stoc/source/security/file_policy.cxx
new file mode 100644
index 000000000..91f75092b
--- /dev/null
+++ b/stoc/source/security/file_policy.cxx
@@ -0,0 +1,493 @@
+/* -*- 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/file.h>
+#include <rtl/byteseq.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/access_control.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/security/XPolicy.hpp>
+#include <com/sun/star/security/AllPermission.hpp>
+#include <com/sun/star/security/RuntimePermission.hpp>
+#include <com/sun/star/io/FilePermission.hpp>
+#include <com/sun/star/connection/SocketPermission.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <string_view>
+#include <unordered_map>
+
+constexpr OUStringLiteral IMPL_NAME = u"com.sun.star.security.comp.stoc.FilePolicy";
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+namespace {
+
+typedef WeakComponentImplHelper< security::XPolicy, lang::XServiceInfo > t_helper;
+
+
+class FilePolicy
+ : public cppu::BaseMutex
+ , public t_helper
+{
+ Reference< XComponentContext > m_xComponentContext;
+ AccessControl m_ac;
+
+ Sequence< Any > m_defaultPermissions;
+ typedef std::unordered_map< OUString, Sequence< Any > > t_permissions;
+ t_permissions m_userPermissions;
+ bool m_init;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit FilePolicy( Reference< XComponentContext > const & xComponentContext );
+
+ // XPolicy impl
+ virtual Sequence< Any > SAL_CALL getPermissions(
+ OUString const & userId ) override;
+ virtual Sequence< Any > SAL_CALL getDefaultPermissions() override;
+ virtual void SAL_CALL refresh() override;
+
+ // XServiceInfo impl
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+};
+
+FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
+ : t_helper( m_aMutex )
+ , m_xComponentContext( xComponentContext )
+ , m_ac( xComponentContext )
+ , m_init( false )
+{}
+
+void FilePolicy::disposing()
+{
+ m_userPermissions.clear();
+ m_defaultPermissions = Sequence< Any >();
+ m_xComponentContext.clear();
+}
+
+
+Sequence< Any > FilePolicy::getPermissions(
+ OUString const & userId )
+{
+ if (! m_init)
+ {
+ refresh();
+ m_init = true;
+ }
+
+ MutexGuard guard( m_aMutex );
+ t_permissions::iterator iFind( m_userPermissions.find( userId ) );
+ if (m_userPermissions.end() == iFind)
+ {
+ return Sequence< Any >();
+ }
+ else
+ {
+ return iFind->second;
+ }
+}
+
+Sequence< Any > FilePolicy::getDefaultPermissions()
+{
+ if (! m_init)
+ {
+ refresh();
+ m_init = true;
+ }
+
+ MutexGuard guard( m_aMutex );
+ return m_defaultPermissions;
+}
+
+
+class PolicyReader
+{
+ OUString m_fileName;
+ oslFileHandle m_file;
+
+ sal_Int32 m_linepos;
+ rtl::ByteSequence m_line;
+ sal_Int32 m_pos;
+ sal_Unicode m_back;
+
+ sal_Unicode get();
+ void back( sal_Unicode c )
+ { m_back = c; }
+
+ static bool isWhiteSpace( sal_Unicode c )
+ { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
+ void skipWhiteSpace();
+
+ static bool isCharToken( sal_Unicode c )
+ { return (';' == c || ',' == c || '{' == c || '}' == c); }
+
+public:
+ PolicyReader( OUString const & file, AccessControl & ac );
+ ~PolicyReader();
+
+ void error( std::u16string_view msg );
+
+ OUString getToken();
+ OUString assureToken();
+ OUString getQuotedToken();
+ OUString assureQuotedToken();
+ void assureToken( sal_Unicode token );
+};
+
+void PolicyReader::assureToken( sal_Unicode token )
+{
+ skipWhiteSpace();
+ sal_Unicode c = get();
+ if (c == token)
+ return;
+ OUString msg = "expected >" + OUStringChar(c) + "<!";
+ error( msg );
+}
+
+OUString PolicyReader::assureQuotedToken()
+{
+ OUString token( getQuotedToken() );
+ if (token.isEmpty())
+ error( u"unexpected end of file!" );
+ return token;
+}
+
+OUString PolicyReader::getQuotedToken()
+{
+ skipWhiteSpace();
+ OUStringBuffer buf( 32 );
+ sal_Unicode c = get();
+ if ('\"' != c)
+ error( u"expected quoting >\"< character!" );
+ c = get();
+ while ('\0' != c && '\"' != c)
+ {
+ buf.append( c );
+ c = get();
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString PolicyReader::assureToken()
+{
+ OUString token( getToken() );
+ if ( token.isEmpty())
+ error( u"unexpected end of file!" );
+ return token;
+}
+
+OUString PolicyReader::getToken()
+{
+ skipWhiteSpace();
+ sal_Unicode c = get();
+ if (isCharToken( c ))
+ return OUString( &c, 1 );
+ OUStringBuffer buf( 32 );
+ while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
+ {
+ buf.append( c );
+ c = get();
+ }
+ back( c );
+ return buf.makeStringAndClear();
+}
+
+void PolicyReader::skipWhiteSpace()
+{
+ sal_Unicode c;
+ do
+ {
+ c = get();
+ }
+ while (isWhiteSpace( c )); // seeking next non-whitespace char
+
+ if ('/' == c) // C/C++ like comment
+ {
+ c = get();
+ if ('/' == c) // C++ like comment
+ {
+ do
+ {
+ c = get();
+ }
+ while ('\n' != c && '\0' != c); // seek eol/eof
+ skipWhiteSpace(); // cont skip on next line
+ }
+ else if ('*' == c) // C like comment
+ {
+ bool fini = true;
+ do
+ {
+ c = get();
+ if ('*' == c)
+ {
+ c = get();
+ fini = ('/' == c || '\0' == c);
+ }
+ else
+ {
+ fini = ('\0' == c);
+ }
+ }
+ while (! fini);
+ skipWhiteSpace(); // cont skip on next line
+ }
+ else
+ {
+ error( u"expected C/C++ like comment!" );
+ }
+ }
+ else if ('#' == c) // script like comment
+ {
+ do
+ {
+ c = get();
+ }
+ while ('\n' != c && '\0' != c); // seek eol/eof
+ skipWhiteSpace(); // cont skip on next line
+ }
+
+ else // is token char
+ {
+ back( c );
+ }
+}
+
+sal_Unicode PolicyReader::get()
+{
+ if ('\0' != m_back) // one char push back possible
+ {
+ sal_Unicode c = m_back;
+ m_back = '\0';
+ return c;
+ }
+ else if (m_pos == m_line.getLength()) // provide newline as whitespace
+ {
+ ++m_pos;
+ return '\n';
+ }
+ else if (m_pos > m_line.getLength()) // read new line
+ {
+ sal_Bool eof;
+ oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
+ if (osl_File_E_None != rc)
+ error( u"checking eof failed!" );
+ if (eof)
+ return '\0';
+
+ rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
+ if (osl_File_E_None != rc)
+ error( u"read line failed!" );
+ ++m_linepos;
+ if (! m_line.getLength()) // empty line read
+ {
+ m_pos = 1; // read new line next time
+ return '\n';
+ }
+ m_pos = 0;
+ }
+ return (m_line.getConstArray()[ m_pos++ ]);
+}
+
+void PolicyReader::error( std::u16string_view msg )
+{
+ throw RuntimeException(
+ "error processing file \"" + m_fileName +
+ "\" [line " + OUString::number(m_linepos) +
+ ", column " + OUString::number(m_pos) +
+ "] " + msg);
+}
+
+PolicyReader::PolicyReader( OUString const & fileName, AccessControl & ac )
+ : m_fileName( fileName )
+ , m_linepos( 0 )
+ , m_pos( 1 ) // force readline
+ , m_back( '\0' )
+{
+ ac.checkFilePermission( m_fileName, "read" );
+ if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
+ {
+ throw RuntimeException( "cannot open file \"" + m_fileName + "\"!" );
+ }
+}
+
+PolicyReader::~PolicyReader()
+{
+ if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
+ OSL_ASSERT( false );
+ }
+}
+
+constexpr OUStringLiteral s_grant = u"grant";
+constexpr OUStringLiteral s_user = u"user";
+constexpr OUStringLiteral s_permission = u"permission";
+constexpr OUStringLiteral s_openBrace = u"{";
+constexpr OUStringLiteral s_closingBrace = u"}";
+
+constexpr OUStringLiteral s_filePermission = u"com.sun.star.io.FilePermission";
+constexpr OUStringLiteral s_socketPermission = u"com.sun.star.connection.SocketPermission";
+constexpr OUStringLiteral s_runtimePermission = u"com.sun.star.security.RuntimePermission";
+constexpr OUStringLiteral s_allPermission = u"com.sun.star.security.AllPermission";
+
+
+void FilePolicy::refresh()
+{
+ // read out file (the .../file-name value had originally been set in
+ // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
+ // depending on various UNO_AC* bootstrap variables that are no longer
+ // supported, so this is effectively dead code):
+ OUString fileName;
+ m_xComponentContext->getValueByName(
+ "/implementations/" + IMPL_NAME + "/file-name" ) >>= fileName;
+ if ( fileName.isEmpty() )
+ {
+ throw RuntimeException(
+ "name of policy file unknown!",
+ static_cast<OWeakObject *>(this) );
+ }
+
+ PolicyReader reader( fileName, m_ac );
+
+ // fill these two
+ Sequence< Any > defaultPermissions;
+ t_permissions userPermissions;
+
+ OUString token( reader.getToken() );
+ while (!token.isEmpty())
+ {
+ if ( token != s_grant )
+ reader.error( u"expected >grant< token!" );
+ OUString userId;
+ token = reader.assureToken();
+ if ( token == s_user ) // next token is user-id
+ {
+ userId = reader.assureQuotedToken();
+ token = reader.assureToken();
+ }
+ if ( token != s_openBrace )
+ reader.error( u"expected opening brace >{<!" );
+ token = reader.assureToken();
+ // permissions list
+ while ( token != s_closingBrace )
+ {
+ if ( token != s_permission )
+ reader.error( u"expected >permission< or closing brace >}<!" );
+
+ token = reader.assureToken(); // permission type
+ Any perm;
+ if ( token == s_filePermission ) // FilePermission
+ {
+ OUString url( reader.assureQuotedToken() );
+ reader.assureToken( ',' );
+ OUString actions( reader.assureQuotedToken() );
+ perm <<= io::FilePermission( url, actions );
+ }
+ else if ( token == s_socketPermission ) // SocketPermission
+ {
+ OUString host( reader.assureQuotedToken() );
+ reader.assureToken( ',' );
+ OUString actions( reader.assureQuotedToken() );
+ perm <<= connection::SocketPermission( host, actions );
+ }
+ else if ( token == s_runtimePermission ) // RuntimePermission
+ {
+ OUString name( reader.assureQuotedToken() );
+ perm <<= security::RuntimePermission( name );
+ }
+ else if ( token == s_allPermission ) // AllPermission
+ {
+ perm <<= security::AllPermission();
+ }
+ else
+ {
+ reader.error( u"expected permission type!" );
+ }
+
+ reader.assureToken( ';' );
+
+ // insert
+ if (!userId.isEmpty())
+ {
+ Sequence< Any > perms( userPermissions[ userId ] );
+ sal_Int32 len = perms.getLength();
+ perms.realloc( len +1 );
+ perms.getArray()[ len ] = perm;
+ userPermissions[ userId ] = perms;
+ }
+ else
+ {
+ sal_Int32 len = defaultPermissions.getLength();
+ defaultPermissions.realloc( len +1 );
+ defaultPermissions.getArray()[ len ] = perm;
+ }
+
+ token = reader.assureToken(); // next permissions token
+ }
+
+ reader.assureToken( ';' ); // semi
+ token = reader.getToken(); // next grant token
+ }
+
+ // assign new ones
+ MutexGuard guard( m_aMutex );
+ m_defaultPermissions = defaultPermissions;
+ m_userPermissions = userPermissions;
+}
+
+
+OUString FilePolicy::getImplementationName()
+{
+ return IMPL_NAME;
+}
+
+sal_Bool FilePolicy::supportsService( OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+Sequence< OUString > FilePolicy::getSupportedServiceNames()
+{
+ return { "com.sun.star.security.Policy" };
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_security_comp_stoc_FilePolicy_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FilePolicy(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/lru_cache.h b/stoc/source/security/lru_cache.h
new file mode 100644
index 000000000..402b41d58
--- /dev/null
+++ b/stoc/source/security/lru_cache.h
@@ -0,0 +1,210 @@
+/* -*- 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 .
+ */
+#ifndef INCLUDED_STOC_SOURCE_SECURITY_LRU_CACHE_H
+#define INCLUDED_STOC_SOURCE_SECURITY_LRU_CACHE_H
+
+#include <memory>
+#include <unordered_map>
+
+// __CACHE_DIAGNOSE works only for OUString keys
+#ifdef __CACHE_DIAGNOSE
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/string.hxx>
+#include <sal/log.hxx>
+#endif
+
+
+namespace stoc_sec
+{
+
+/** Implementation of a least recently used (lru) cache.
+*/
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+class lru_cache
+{
+ struct Entry
+ {
+ t_key m_key;
+ t_val m_val;
+ Entry * m_pred;
+ Entry * m_succ;
+ };
+ typedef std::unordered_map< t_key, Entry *, t_hashKey, t_equalKey > t_key2element;
+ t_key2element m_key2element;
+ ::std::size_t m_size;
+
+ std::unique_ptr<Entry[]> m_block;
+ mutable Entry * m_head;
+ mutable Entry * m_tail;
+ inline void toFront( Entry * entry ) const;
+
+public:
+ /** Default Ctor. Does not cache.
+ */
+ inline lru_cache();
+
+ /** Retrieves a pointer to value in cache. Returns 0, if none was found.
+
+ @param key a key
+ @return pointer to value or 0
+ */
+ inline t_val const * lookup( t_key const & key ) const;
+
+ /** Sets a value to be cached for given key.
+
+ @param key a key
+ @param val a value
+ */
+ inline void set( t_key const & key, t_val const & val );
+
+ /** Sets the number of elements to be cached. This will clear previous entries.
+
+ @param cacheSize number of elements to be cached
+ */
+ inline void setSize( ::std::size_t size );
+};
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::setSize(
+ ::std::size_t size )
+{
+ m_key2element.clear();
+ m_block.reset();
+ m_size = size;
+
+ if (0 < m_size)
+ {
+ m_block.reset( new Entry[ m_size ] );
+ m_head = m_block.get();
+ m_tail = m_block.get() + m_size -1;
+ for ( ::std::size_t nPos = m_size; nPos--; )
+ {
+ m_block[ nPos ].m_pred = m_block.get() + nPos -1;
+ m_block[ nPos ].m_succ = m_block.get() + nPos +1;
+ }
+ }
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline lru_cache< t_key, t_val, t_hashKey, t_equalKey >::lru_cache()
+ : m_size( 0 )
+ , m_block( nullptr )
+ , m_head( nullptr )
+ , m_tail( nullptr )
+{
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::toFront(
+ Entry * entry ) const
+{
+ if (entry != m_head)
+ {
+ // cut out element
+ if (entry == m_tail)
+ {
+ m_tail = entry->m_pred;
+ }
+ else
+ {
+ entry->m_succ->m_pred = entry->m_pred;
+ entry->m_pred->m_succ = entry->m_succ;
+ }
+ // push to front
+ m_head->m_pred = entry;
+ entry->m_succ = m_head;
+ m_head = entry;
+ }
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline t_val const * lru_cache< t_key, t_val, t_hashKey, t_equalKey >::lookup(
+ t_key const & key ) const
+{
+ if (0 < m_size)
+ {
+ typename t_key2element::const_iterator const iFind( m_key2element.find( key ) );
+ if (iFind != m_key2element.end())
+ {
+ Entry * entry = iFind->second;
+ toFront( entry );
+#ifdef __CACHE_DIAGNOSE
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> retrieved element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" from cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+#endif
+ return &entry->m_val;
+ }
+ }
+ return nullptr;
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::set(
+ t_key const & key, t_val const & val )
+{
+ if (0 < m_size)
+ {
+ typename t_key2element::const_iterator const iFind( m_key2element.find( key ) );
+
+ Entry * entry;
+ if (iFind == m_key2element.end())
+ {
+ entry = m_tail; // erase last element
+#ifdef __CACHE_DIAGNOSE
+ if (entry->m_key.getLength())
+ {
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> kicking element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" from cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+ }
+#endif
+ m_key2element.erase( entry->m_key );
+ entry->m_key = key;
+ ::std::pair< typename t_key2element::iterator, bool > insertion(
+ m_key2element.emplace( key, entry ) );
+ OSL_ENSURE( insertion.second, "### inserting new cache entry failed?!" );
+ }
+ else
+ {
+ entry = iFind->second;
+#ifdef __CACHE_DIAGNOSE
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> replacing element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" in cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+#endif
+ }
+ entry->m_val = val;
+ toFront( entry );
+ }
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/permissions.cxx b/stoc/source/security/permissions.cxx
new file mode 100644
index 000000000..1799f9c8c
--- /dev/null
+++ b/stoc/source/security/permissions.cxx
@@ -0,0 +1,604 @@
+/* -*- 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 <vector>
+
+#include <osl/process.h>
+#include <osl/socket.hxx>
+#include <osl/mutex.hxx>
+
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/security/RuntimePermission.hpp>
+#include <com/sun/star/security/AllPermission.hpp>
+#include <com/sun/star/io/FilePermission.hpp>
+#include <com/sun/star/connection/SocketPermission.hpp>
+#include <com/sun/star/security/AccessControlException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "permissions.h"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+namespace stoc_sec
+{
+
+
+static sal_Int32 makeMask(
+ OUString const & items, char const * const * strings )
+{
+ sal_Int32 mask = 0;
+
+ sal_Int32 n = 0;
+ do
+ {
+ OUString item( o3tl::trim(o3tl::getToken(items, 0, ',', n )) );
+ if ( item.isEmpty())
+ continue;
+ sal_Int32 nPos = 0;
+ while (strings[ nPos ])
+ {
+ if (item.equalsAscii( strings[ nPos ] ))
+ {
+ mask |= (0x80000000 >> nPos);
+ break;
+ }
+ ++nPos;
+ }
+#if OSL_DEBUG_LEVEL > 0
+ if (! strings[ nPos ])
+ {
+ SAL_WARN("stoc", "ignoring unknown socket action: " << item );
+ }
+#endif
+ }
+ while (n >= 0); // all items
+ return mask;
+}
+
+static OUString makeStrings(
+ sal_Int32 mask, char const * const * strings )
+{
+ OUStringBuffer buf( 48 );
+ while (mask)
+ {
+ if (0x80000000 & mask)
+ {
+ buf.appendAscii( *strings );
+ if ((mask << 1) != 0) // more items following
+ buf.append( ',' );
+ }
+ mask = (mask << 1);
+ ++strings;
+ }
+ return buf.makeStringAndClear();
+}
+
+namespace {
+
+class SocketPermission : public Permission
+{
+ static char const * s_actions [];
+ sal_Int32 m_actions;
+
+ OUString m_host;
+ sal_Int32 m_lowerPort;
+ sal_Int32 m_upperPort;
+ mutable OUString m_ip;
+ mutable bool m_resolveErr;
+ mutable bool m_resolvedHost;
+ bool m_wildCardHost;
+
+ inline bool resolveHost() const;
+
+public:
+ SocketPermission(
+ connection::SocketPermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() );
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+char const * SocketPermission::s_actions [] = { "accept", "connect", "listen", "resolve", nullptr };
+
+SocketPermission::SocketPermission(
+ connection::SocketPermission const & perm,
+ ::rtl::Reference< Permission > const & next )
+ : Permission( SOCKET, next )
+ , m_actions( makeMask( perm.Actions, s_actions ) )
+ , m_host( perm.Host )
+ , m_lowerPort( 0 )
+ , m_upperPort( 65535 )
+ , m_resolveErr( false )
+ , m_resolvedHost( false )
+ , m_wildCardHost( !perm.Host.isEmpty() && '*' == perm.Host.pData->buffer[ 0 ] )
+{
+ if (0xe0000000 & m_actions) // if any (except resolve) is given => resolve implied
+ m_actions |= 0x10000000;
+
+ // separate host from portrange
+ sal_Int32 colon = m_host.indexOf( ':' );
+ if (colon < 0) // port [range] not given
+ return;
+
+ sal_Int32 minus = m_host.indexOf( '-', colon +1 );
+ if (minus < 0)
+ {
+ m_lowerPort = m_upperPort = o3tl::toInt32(m_host.subView( colon +1 ));
+ }
+ else if (minus == (colon +1)) // -N
+ {
+ m_upperPort = o3tl::toInt32(m_host.subView( minus +1 ));
+ }
+ else if (minus == (m_host.getLength() -1)) // N-
+ {
+ m_lowerPort = o3tl::toInt32(m_host.subView( colon +1, m_host.getLength() -1 -colon -1 ));
+ }
+ else // A-B
+ {
+ m_lowerPort = o3tl::toInt32(m_host.subView( colon +1, minus - colon -1 ));
+ m_upperPort = o3tl::toInt32(m_host.subView( minus +1 ));
+ }
+ m_host = m_host.copy( 0, colon );
+}
+
+inline bool SocketPermission::resolveHost() const
+{
+ if (m_resolveErr)
+ return false;
+
+ if (! m_resolvedHost)
+ {
+ // dns lookup
+ SocketAddr addr;
+ SocketAddr::resolveHostname( m_host, addr );
+ OUString ip;
+ m_resolveErr = (::osl_Socket_Ok != ::osl_getDottedInetAddrOfSocketAddr(
+ addr.getHandle(), &ip.pData ));
+ if (m_resolveErr)
+ return false;
+
+ MutexGuard guard( Mutex::getGlobalMutex() );
+ if (! m_resolvedHost)
+ {
+ m_ip = ip;
+ m_resolvedHost = true;
+ }
+ }
+ return m_resolvedHost;
+}
+
+bool SocketPermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (SOCKET != perm.m_type)
+ return false;
+ SocketPermission const & demanded = static_cast< SocketPermission const & >( perm );
+
+ // check actions
+ if ((m_actions & demanded.m_actions) != demanded.m_actions)
+ return false;
+
+ // check ports
+ if (demanded.m_lowerPort < m_lowerPort)
+ return false;
+ if (demanded.m_upperPort > m_upperPort)
+ return false;
+
+ // quick check host (DNS names: RFC 1034/1035)
+ if (m_host.equalsIgnoreAsciiCase( demanded.m_host ))
+ return true;
+ // check for host wildcards
+ if (m_wildCardHost)
+ {
+ OUString const & demanded_host = demanded.m_host;
+ if (demanded_host.getLength() <= m_host.getLength())
+ return false;
+ sal_Int32 len = m_host.getLength() -1; // skip star
+ return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded_host.getStr() + demanded_host.getLength() - len, len,
+ m_host.pData->buffer + 1, len ));
+ }
+ if (demanded.m_wildCardHost)
+ return false;
+
+ // compare IP addresses
+ if (! resolveHost())
+ return false;
+ if (! demanded.resolveHost())
+ return false;
+ return m_ip == demanded.m_ip;
+}
+
+OUString SocketPermission::toString() const
+{
+ OUStringBuffer buf( 48 );
+ // host
+ buf.append( "com.sun.star.connection.SocketPermission (host=\"" );
+ buf.append( m_host );
+ if (m_resolvedHost)
+ {
+ buf.append( '[' );
+ buf.append( m_ip );
+ buf.append( ']' );
+ }
+ // port
+ if (0 != m_lowerPort || 65535 != m_upperPort)
+ {
+ buf.append( ':' );
+ if (m_lowerPort > 0)
+ buf.append( m_lowerPort );
+ if (m_upperPort > m_lowerPort)
+ {
+ buf.append( '-' );
+ if (m_upperPort < 65535)
+ buf.append( m_upperPort );
+ }
+ }
+ // actions
+ buf.append( "\", actions=\"" );
+ buf.append( makeStrings( m_actions, s_actions ) );
+ buf.append( "\")" );
+ return buf.makeStringAndClear();
+}
+
+namespace {
+
+class FilePermission : public Permission
+{
+ static char const * s_actions [];
+ sal_Int32 m_actions;
+
+ OUString m_url;
+ bool m_allFiles;
+
+public:
+ FilePermission(
+ io::FilePermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() );
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+char const * FilePermission::s_actions [] = { "read", "write", "execute", "delete", nullptr };
+
+static OUString const & getWorkingDir()
+{
+ static OUString s_workingDir = []() {
+ OUString workingDir;
+ ::osl_getProcessWorkingDir(&workingDir.pData);
+ return workingDir;
+ }();
+ return s_workingDir;
+}
+
+FilePermission::FilePermission(
+ io::FilePermission const & perm,
+ ::rtl::Reference< Permission > const & next )
+ : Permission( FILE, next )
+ , m_actions( makeMask( perm.Actions, s_actions ) )
+ , m_url( perm.URL )
+ , m_allFiles( perm.URL == "<<ALL FILES>>" )
+{
+ if ( m_allFiles)
+ return;
+
+ if ( m_url == "*" )
+ {
+ m_url = getWorkingDir() + "/*";
+ }
+ else if ( m_url == "-" )
+ {
+ m_url = getWorkingDir() + "/-";
+ }
+ else if (!m_url.startsWith("file:///"))
+ {
+ // relative path
+ OUString out;
+ oslFileError rc = ::osl_getAbsoluteFileURL(
+ getWorkingDir().pData, perm.URL.pData, &out.pData );
+ m_url = (osl_File_E_None == rc ? out : perm.URL); // fallback
+ }
+#ifdef _WIN32
+ // correct win drive letters
+ if (9 < m_url.getLength() && '|' == m_url[ 9 ]) // file:///X|
+ {
+ constexpr OUStringLiteral s_colon = u":";
+ // common case in API is a ':' (sal), so convert '|' to ':'
+ m_url = m_url.replaceAt( 9, 1, s_colon );
+ }
+#endif
+}
+
+bool FilePermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (FILE != perm.m_type)
+ return false;
+ FilePermission const & demanded = static_cast< FilePermission const & >( perm );
+
+ // check actions
+ if ((m_actions & demanded.m_actions) != demanded.m_actions)
+ return false;
+
+ // check url
+ if (m_allFiles)
+ return true;
+ if (demanded.m_allFiles)
+ return false;
+
+#ifdef _WIN32
+ if (m_url.equalsIgnoreAsciiCase( demanded.m_url ))
+ return true;
+#else
+ if (m_url == demanded.m_url )
+ return true;
+#endif
+ if (m_url.getLength() > demanded.m_url.getLength())
+ return false;
+ // check /- wildcard: all files and recursive in that path
+ if (m_url.endsWith("/-"))
+ {
+ // demanded url must start with granted path (including path trailing path sep)
+ sal_Int32 len = m_url.getLength() -1;
+#ifdef _WIN32
+ return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len ));
+#else
+ return (0 == ::rtl_ustr_reverseCompare_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len ));
+#endif
+ }
+ // check /* wildcard: all files in that path (not recursive!)
+ if (m_url.endsWith("/*"))
+ {
+ // demanded url must start with granted path (including path trailing path sep)
+ sal_Int32 len = m_url.getLength() -1;
+#ifdef _WIN32
+ return ((0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len )) &&
+ (0 > demanded.m_url.indexOf( '/', len ))); // in addition, no deeper paths
+#else
+ return ((0 == ::rtl_ustr_reverseCompare_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len )) &&
+ (0 > demanded.m_url.indexOf( '/', len ))); // in addition, no deeper paths
+#endif
+ }
+ return false;
+}
+
+OUString FilePermission::toString() const
+{
+ return
+ // url
+ "com.sun.star.io.FilePermission (url=\"" + m_url
+ // actions
+ + "\", actions=\"" + makeStrings( m_actions, s_actions ) + "\")";
+}
+
+namespace {
+
+class RuntimePermission : public Permission
+{
+ OUString m_name;
+
+public:
+ RuntimePermission(
+ security::RuntimePermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() )
+ : Permission( RUNTIME, next )
+ , m_name( perm.Name )
+ {}
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+bool RuntimePermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (RUNTIME != perm.m_type)
+ return false;
+ RuntimePermission const & demanded = static_cast< RuntimePermission const & >( perm );
+
+ // check name
+ return m_name == demanded.m_name;
+}
+
+OUString RuntimePermission::toString() const
+{
+ return "com.sun.star.security.RuntimePermission (name=\"" +
+ m_name + "\")";
+}
+
+
+bool AllPermission::implies( Permission const & ) const
+{
+ return true;
+}
+
+OUString AllPermission::toString() const
+{
+ return "com.sun.star.security.AllPermission";
+}
+
+
+PermissionCollection::PermissionCollection(
+ Sequence< Any > const & permissions, PermissionCollection const & addition )
+ : m_head( addition.m_head )
+{
+ Any const * perms = permissions.getConstArray();
+ for ( sal_Int32 nPos = permissions.getLength(); nPos--; )
+ {
+ Any const & perm = perms[ nPos ];
+ Type const & perm_type = perm.getValueType();
+
+ // supported permission types
+ if (perm_type.equals( cppu::UnoType<io::FilePermission>::get()))
+ {
+ m_head = new FilePermission(
+ *static_cast< io::FilePermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<connection::SocketPermission>::get()))
+ {
+ m_head = new SocketPermission(
+ *static_cast< connection::SocketPermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<security::RuntimePermission>::get()))
+ {
+ m_head = new RuntimePermission(
+ *static_cast< security::RuntimePermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<security::AllPermission>::get()))
+ {
+ m_head = new AllPermission( m_head );
+ }
+ else
+ {
+ throw RuntimeException( "checking for unsupported permission type: " + perm_type.getTypeName() );
+ }
+ }
+}
+#ifdef __DIAGNOSE
+
+Sequence< OUString > PermissionCollection::toStrings() const
+{
+ vector< OUString > strings;
+ strings.reserve( 8 );
+ for ( Permission * perm = m_head.get(); perm; perm = perm->m_next.get() )
+ {
+ strings.push_back( perm->toString() );
+ }
+ return Sequence< OUString >( strings.data(), strings.size() );
+}
+#endif
+
+static bool implies(
+ ::rtl::Reference< Permission > const & head, Permission const & demanded )
+{
+ for ( Permission * perm = head.get(); perm; perm = perm->m_next.get() )
+ {
+ if (perm->implies( demanded ))
+ return true;
+ }
+ return false;
+}
+
+#ifdef __DIAGNOSE
+
+static void demanded_diag(
+ Permission const & perm )
+{
+ OUStringBuffer buf( 48 );
+ buf.append( "demanding " );
+ buf.append( perm.toString() );
+ buf.append( " => ok." );
+ OString str(
+ OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
+ SAL_INFO("stoc",( "%s", str.getStr() );
+}
+#endif
+
+static void throwAccessControlException(
+ Permission const & perm, Any const & demanded_perm )
+{
+ throw security::AccessControlException(
+ "access denied: " + perm.toString(),
+ Reference< XInterface >(), demanded_perm );
+}
+
+void PermissionCollection::checkPermission( Any const & perm ) const
+{
+ Type const & demanded_type = perm.getValueType();
+
+ // supported permission types
+ // stack object of SimpleReferenceObject are ok, as long as they are not
+ // assigned to a ::rtl::Reference<> (=> delete this)
+ if (demanded_type.equals( cppu::UnoType<io::FilePermission>::get()))
+ {
+ FilePermission demanded(
+ *static_cast< io::FilePermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<connection::SocketPermission>::get()))
+ {
+ SocketPermission demanded(
+ *static_cast< connection::SocketPermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<security::RuntimePermission>::get()))
+ {
+ RuntimePermission demanded(
+ *static_cast< security::RuntimePermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<security::AllPermission>::get()))
+ {
+ AllPermission demanded;
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else
+ {
+ throw RuntimeException( "checking for unsupported permission type: " + demanded_type.getTypeName() );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/permissions.h b/stoc/source/security/permissions.h
new file mode 100644
index 000000000..eb0b30778
--- /dev/null
+++ b/stoc/source/security/permissions.h
@@ -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 .
+ */
+#ifndef INCLUDED_STOC_SOURCE_SECURITY_PERMISSIONS_H
+#define INCLUDED_STOC_SOURCE_SECURITY_PERMISSIONS_H
+
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace com::sun::star::uno { class Any; }
+namespace com::sun::star::uno { template <class E> class Sequence; }
+
+namespace stoc_sec
+{
+
+class Permission : public ::salhelper::SimpleReferenceObject
+{
+public:
+ ::rtl::Reference< Permission > m_next;
+ // mode
+ enum t_type { ALL, RUNTIME, SOCKET, FILE } m_type;
+
+ Permission(
+ t_type type,
+ ::rtl::Reference< Permission > const & next )
+ : m_next( next )
+ , m_type( type )
+ {}
+
+ virtual bool implies( Permission const & perm ) const = 0;
+ virtual OUString toString() const = 0;
+};
+
+class AllPermission : public Permission
+{
+public:
+ explicit AllPermission(
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() )
+ : Permission( ALL, next )
+ {}
+
+ virtual bool implies( Permission const & ) const override;
+ virtual OUString toString() const override;
+};
+
+
+class PermissionCollection
+{
+ ::rtl::Reference< Permission > m_head;
+public:
+ PermissionCollection()
+ {}
+ explicit PermissionCollection( ::rtl::Reference< Permission > const & single )
+ : m_head( single )
+ {}
+ PermissionCollection(
+ css::uno::Sequence< css::uno::Any > const & permissions,
+ PermissionCollection const & addition = PermissionCollection() );
+#ifdef __DIAGNOSE
+ css::uno::Sequence< OUString > toStrings() const;
+#endif
+ void checkPermission( css::uno::Any const & perm ) const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/servicemanager/servicemanager.cxx b/stoc/source/servicemanager/servicemanager.cxx
new file mode 100644
index 000000000..77651b0f0
--- /dev/null
+++ b/stoc/source/servicemanager/servicemanager.cxx
@@ -0,0 +1,1476 @@
+/* -*- 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 <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/container/XElementAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <iterator>
+#include <mutex>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::container;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+Sequence< OUString > retrieveAsciiValueList(
+ const Reference< XSimpleRegistry > &xReg, const OUString &keyName )
+{
+ Reference< XEnumerationAccess > xAccess( xReg, UNO_QUERY );
+ Sequence< OUString > seq;
+ if( xAccess.is() )
+ {
+ Reference< XEnumeration > xEnum = xAccess->createEnumeration();
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ Reference< XSimpleRegistry > xTempReg;
+ xEnum->nextElement() >>= xTempReg;
+ if( xTempReg.is() )
+ {
+ const Sequence< OUString > seq2 = retrieveAsciiValueList( xTempReg, keyName );
+
+ if( seq2.hasElements() )
+ {
+ sal_Int32 n1Len = seq.getLength();
+ sal_Int32 n2Len = seq2.getLength();
+
+ seq.realloc( n1Len + n2Len );
+ std::copy(seq2.begin(), seq2.end(), std::next(seq.getArray(), n1Len));
+ }
+ }
+ }
+ }
+ else if( xReg.is () )
+ {
+ try
+ {
+ Reference< XRegistryKey > rRootKey = xReg->getRootKey();
+ if( rRootKey.is() )
+ {
+ Reference<XRegistryKey > xKey = rRootKey->openKey(keyName);
+ if( xKey.is() )
+ {
+ seq = xKey->getAsciiListValue();
+ }
+ }
+ }
+ catch( InvalidRegistryException & )
+ {
+ }
+ catch (InvalidValueException &)
+ {
+ }
+ }
+ return seq;
+}
+
+/*****************************************************************************
+ Enumeration by ServiceName
+*****************************************************************************/
+
+typedef std::unordered_set< Reference<XInterface > > HashSet_Ref;
+
+
+class ServiceEnumeration_Impl : public WeakImplHelper< XEnumeration >
+{
+public:
+ explicit ServiceEnumeration_Impl( const Sequence< Reference<XInterface > > & rFactories )
+ : aFactories( rFactories )
+ , nIt( 0 )
+ {}
+
+ // XEnumeration
+ sal_Bool SAL_CALL hasMoreElements() override;
+ Any SAL_CALL nextElement() override;
+private:
+ std::mutex aMutex;
+ Sequence< Reference<XInterface > > aFactories;
+ sal_Int32 nIt;
+};
+
+// XEnumeration
+sal_Bool ServiceEnumeration_Impl::hasMoreElements()
+{
+ std::scoped_lock aGuard( aMutex );
+ return nIt != aFactories.getLength();
+}
+
+// XEnumeration
+Any ServiceEnumeration_Impl::nextElement()
+{
+ std::scoped_lock aGuard( aMutex );
+ if( nIt == aFactories.getLength() )
+ throw NoSuchElementException("no more elements");
+
+ return Any( &aFactories.getConstArray()[nIt++], cppu::UnoType<XInterface>::get());
+}
+
+
+class PropertySetInfo_Impl : public WeakImplHelper< beans::XPropertySetInfo >
+{
+ Sequence< beans::Property > m_properties;
+
+public:
+ explicit PropertySetInfo_Impl( Sequence< beans::Property > const & properties )
+ : m_properties( properties )
+ {}
+
+ // XPropertySetInfo impl
+ virtual Sequence< beans::Property > SAL_CALL getProperties() override;
+ virtual beans::Property SAL_CALL getPropertyByName( OUString const & name ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( OUString const & name ) override;
+};
+
+Sequence< beans::Property > PropertySetInfo_Impl::getProperties()
+{
+ return m_properties;
+}
+
+beans::Property PropertySetInfo_Impl::getPropertyByName( OUString const & name )
+{
+ beans::Property const * p = m_properties.getConstArray();
+ for ( sal_Int32 nPos = m_properties.getLength(); nPos--; )
+ {
+ if (p[ nPos ].Name == name)
+ return p[ nPos ];
+ }
+ throw beans::UnknownPropertyException(
+ "unknown property: " + name );
+}
+
+sal_Bool PropertySetInfo_Impl::hasPropertyByName( OUString const & name )
+{
+ return std::any_of(std::cbegin(m_properties), std::cend(m_properties),
+ [&name](const beans::Property& rProp) { return rProp.Name == name; });
+}
+
+
+/*****************************************************************************
+ Enumeration by implementation
+*****************************************************************************/
+class ImplementationEnumeration_Impl : public WeakImplHelper< XEnumeration >
+{
+public:
+ explicit ImplementationEnumeration_Impl( const HashSet_Ref & rImplementationMap )
+ : aImplementationMap( rImplementationMap )
+ , aIt( aImplementationMap.begin() )
+ {}
+
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual Any SAL_CALL nextElement() override;
+
+private:
+ std::mutex aMutex;
+ HashSet_Ref aImplementationMap;
+ HashSet_Ref::iterator aIt;
+};
+
+// XEnumeration
+sal_Bool ImplementationEnumeration_Impl::hasMoreElements()
+{
+ std::scoped_lock aGuard( aMutex );
+ return aIt != aImplementationMap.end();
+}
+
+// XEnumeration
+Any ImplementationEnumeration_Impl::nextElement()
+{
+ std::scoped_lock aGuard( aMutex );
+ if( aIt == aImplementationMap.end() )
+ throw NoSuchElementException("no more elements");
+
+ Any ret( &(*aIt), cppu::UnoType<XInterface>::get());
+ ++aIt;
+ return ret;
+}
+
+/*****************************************************************************
+ Hash tables
+*****************************************************************************/
+typedef std::unordered_set
+<
+ OUString
+> HashSet_OWString;
+
+typedef std::unordered_multimap
+<
+ OUString,
+ Reference<XInterface >
+> HashMultimap_OWString_Interface;
+
+typedef std::unordered_map
+<
+ OUString,
+ Reference<XInterface >
+> HashMap_OWString_Interface;
+
+/*****************************************************************************
+ class OServiceManager_Listener
+*****************************************************************************/
+class OServiceManager_Listener : public WeakImplHelper< XEventListener >
+{
+private:
+ WeakReference<XSet > xSMgr;
+
+public:
+ explicit OServiceManager_Listener( const Reference<XSet > & rSMgr )
+ : xSMgr( rSMgr )
+ {}
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const EventObject & rEvt ) override;
+};
+
+void OServiceManager_Listener::disposing(const EventObject & rEvt )
+{
+ Reference<XSet > x( xSMgr );
+ if( !x.is() )
+ return;
+
+ try
+ {
+ x->remove( Any( &rEvt.Source, cppu::UnoType<XInterface>::get()) );
+ }
+ catch( const IllegalArgumentException & )
+ {
+ OSL_FAIL( "IllegalArgumentException caught" );
+ }
+ catch( const NoSuchElementException & )
+ {
+ OSL_FAIL( "NoSuchElementException caught" );
+ }
+}
+
+
+/*****************************************************************************
+ class OServiceManager
+*****************************************************************************/
+
+typedef WeakComponentImplHelper<
+ lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo,
+ lang::XInitialization,
+ container::XSet, container::XContentEnumerationAccess,
+ beans::XPropertySet > t_OServiceManager_impl;
+
+class OServiceManager
+ : public cppu::BaseMutex
+ , public t_OServiceManager_impl
+{
+public:
+ explicit OServiceManager( Reference< XComponentContext > const & xContext );
+
+ // XInitialization
+ void SAL_CALL initialize( Sequence< Any > const & args ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XMultiComponentFactory
+ virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
+ OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override;
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext ) override;
+// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames()
+// throw (RuntimeException);
+
+ // XMultiServiceFactory
+ virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override;
+ virtual Reference<XInterface > SAL_CALL createInstance(const OUString &) override;
+ virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString &, const Sequence<Any >& Arguments) override;
+
+ // The same as the getAvailableServiceNames, but only unique names
+ Sequence< OUString > getUniqueAvailableServiceNames(
+ HashSet_OWString & aNameSet );
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XEnumerationAccess
+ virtual Reference<XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XSet
+ virtual sal_Bool SAL_CALL has( const Any & Element ) override;
+ virtual void SAL_CALL insert( const Any & Element ) override;
+ virtual void SAL_CALL remove( const Any & Element ) override;
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XPropertySet
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+ void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override;
+ void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override;
+ void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override;
+ void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override;
+
+protected:
+ bool is_disposed() const;
+ void check_undisposed() const;
+ virtual void SAL_CALL disposing() override;
+
+ bool haveFactoryWithThisImplementation(const OUString& aImplName);
+
+ virtual Sequence< Reference< XInterface > > queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext );
+
+ Reference< XComponentContext > m_xContext;
+
+ Reference< beans::XPropertySetInfo > m_xPropertyInfo;
+
+ // factories which have been loaded and not inserted( by XSet::insert)
+ // are remembered by this set.
+ HashSet_Ref m_SetLoadedFactories;
+private:
+
+ Reference<XEventListener > getFactoryListener();
+
+
+ HashMultimap_OWString_Interface m_ServiceMap;
+ HashSet_Ref m_ImplementationMap;
+ HashMap_OWString_Interface m_ImplementationNameMap;
+ Reference<XEventListener > xFactoryListener;
+ bool m_bInDisposing;
+};
+
+
+bool OServiceManager::is_disposed() const
+{
+ // ought to be guarded by m_mutex:
+ return (m_bInDisposing || rBHelper.bDisposed);
+}
+
+
+void OServiceManager::check_undisposed() const
+{
+ if (is_disposed())
+ {
+ throw lang::DisposedException(
+ "service manager instance has already been disposed!",
+ static_cast<OWeakObject *>(const_cast<OServiceManager *>(this)) );
+ }
+}
+
+
+typedef WeakComponentImplHelper<
+ lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo,
+ container::XSet, container::XContentEnumerationAccess,
+ beans::XPropertySet > t_OServiceManagerWrapper_impl;
+
+class OServiceManagerWrapper : public cppu::BaseMutex, public t_OServiceManagerWrapper_impl
+{
+ Reference< XComponentContext > m_xContext;
+ Reference< XMultiComponentFactory > m_root;
+ Reference< XMultiComponentFactory > const & getRoot() const
+ {
+ if (! m_root.is())
+ {
+ throw lang::DisposedException(
+ "service manager instance has already been disposed!" );
+ }
+ return m_root;
+ }
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit OServiceManagerWrapper(
+ Reference< XComponentContext > const & xContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getImplementationName(); }
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->supportsService( ServiceName ); }
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getSupportedServiceNames(); }
+
+ // XMultiComponentFactory
+ virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
+ OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override
+ { return getRoot()->createInstanceWithContext( rServiceSpecifier, xContext ); }
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext ) override
+ { return getRoot()->createInstanceWithArgumentsAndContext( rServiceSpecifier, rArguments, xContext ); }
+// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames()
+// throw (RuntimeException);
+
+ // XMultiServiceFactory
+ virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override
+ { return getRoot()->getAvailableServiceNames(); }
+ virtual Reference<XInterface > SAL_CALL createInstance(const OUString & name) override
+ { return getRoot()->createInstanceWithContext( name, m_xContext ); }
+ virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString & name, const Sequence<Any >& Arguments) override
+ { return getRoot()->createInstanceWithArgumentsAndContext( name, Arguments, m_xContext ); }
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->getElementType(); }
+ virtual sal_Bool SAL_CALL hasElements() override
+ { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->hasElements(); }
+
+ // XEnumerationAccess
+ virtual Reference<XEnumeration > SAL_CALL createEnumeration() override
+ { return Reference< XEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createEnumeration(); }
+
+ // XSet
+ virtual sal_Bool SAL_CALL has( const Any & Element ) override
+ { return Reference< XSet >(getRoot(), UNO_QUERY_THROW)->has( Element ); }
+ virtual void SAL_CALL insert( const Any & Element ) override
+ { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->insert( Element ); }
+ virtual void SAL_CALL remove( const Any & Element ) override
+ { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->remove( Element ); }
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override
+ { return Reference< XContentEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createContentEnumeration( aServiceName ); }
+
+ // XPropertySet
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override
+ { return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertySetInfo(); }
+
+ void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+
+ void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addPropertyChangeListener( PropertyName, aListener ); }
+ void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removePropertyChangeListener( PropertyName, aListener ); }
+ void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addVetoableChangeListener( PropertyName, aListener ); }
+ void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removeVetoableChangeListener( PropertyName, aListener ); }
+};
+
+void SAL_CALL OServiceManagerWrapper::setPropertyValue(
+ const OUString& PropertyName, const Any& aValue )
+{
+ if ( PropertyName == "DefaultContext" )
+ {
+ Reference< XComponentContext > xContext;
+ if (!(aValue >>= xContext))
+ {
+ throw IllegalArgumentException(
+ "no XComponentContext given!",
+ static_cast<OWeakObject *>(this), 1 );
+ }
+
+ MutexGuard aGuard( m_aMutex );
+ m_xContext = xContext;
+
+ }
+ else
+ {
+ Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->setPropertyValue( PropertyName, aValue );
+ }
+}
+
+Any SAL_CALL OServiceManagerWrapper::getPropertyValue(
+ const OUString& PropertyName )
+{
+ if ( PropertyName == "DefaultContext" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xContext.is() )
+ return Any( m_xContext );
+ else
+ return Any();
+ }
+ else
+ {
+ return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertyValue( PropertyName );
+ }
+}
+
+void OServiceManagerWrapper::disposing()
+{
+ m_xContext.clear();
+
+// no m_root->dispose(), because every context disposes its service manager...
+ m_root.clear();
+}
+
+OServiceManagerWrapper::OServiceManagerWrapper(
+ Reference< XComponentContext > const & xContext )
+ : t_OServiceManagerWrapper_impl( m_aMutex )
+ , m_xContext( xContext )
+ , m_root( xContext->getServiceManager() )
+{
+ if (! m_root.is())
+ {
+ throw RuntimeException(
+ "no service manager to wrap" );
+ }
+}
+
+
+/**
+ * Create a ServiceManager
+ */
+OServiceManager::OServiceManager( Reference< XComponentContext > const & xContext )
+ : t_OServiceManager_impl( m_aMutex )
+ , m_xContext( xContext )
+ , m_bInDisposing( false )
+{}
+
+// XComponent
+void OServiceManager::dispose()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ return;
+ t_OServiceManager_impl::dispose();
+}
+
+void OServiceManager::disposing()
+{
+ // dispose all factories
+ HashSet_Ref aImpls;
+ {
+ MutexGuard aGuard( m_aMutex );
+ m_bInDisposing = true;
+ aImpls = m_ImplementationMap;
+ }
+ for( const auto& rxImpl : aImpls )
+ {
+ try
+ {
+ Reference<XComponent > xComp( Reference<XComponent >::query( rxImpl ) );
+ if( xComp.is() )
+ xComp->dispose();
+ }
+ catch (const RuntimeException & exc)
+ {
+ SAL_INFO("stoc", "RuntimeException occurred upon disposing factory: " << exc);
+ }
+ }
+
+ // dispose
+ HashSet_Ref aImplMap;
+ {
+ MutexGuard aGuard( m_aMutex );
+ // erase all members
+ m_ServiceMap = HashMultimap_OWString_Interface();
+ aImplMap = m_ImplementationMap;
+ m_ImplementationMap = HashSet_Ref();
+ m_ImplementationNameMap = HashMap_OWString_Interface();
+ m_SetLoadedFactories= HashSet_Ref();
+ }
+
+ m_xContext.clear();
+
+ // not only the Event should hold the object
+ OSL_ASSERT( m_refCount != 1 );
+}
+
+// XPropertySet
+Reference<XPropertySetInfo > OServiceManager::getPropertySetInfo()
+{
+ check_undisposed();
+ if (! m_xPropertyInfo.is())
+ {
+ Sequence< beans::Property > seq{ beans::Property(
+ "DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0 ) };
+ Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) );
+
+ MutexGuard aGuard( m_aMutex );
+ if (! m_xPropertyInfo.is())
+ {
+ m_xPropertyInfo = xInfo;
+ }
+ }
+ return m_xPropertyInfo;
+}
+
+void OServiceManager::setPropertyValue(
+ const OUString& PropertyName, const Any& aValue )
+{
+ check_undisposed();
+ if ( PropertyName != "DefaultContext" )
+ {
+ throw UnknownPropertyException(
+ "unknown property " + PropertyName,
+ static_cast<OWeakObject *>(this) );
+ }
+
+ Reference< XComponentContext > xContext;
+ if (!(aValue >>= xContext))
+ {
+ throw IllegalArgumentException(
+ "no XComponentContext given!",
+ static_cast<OWeakObject *>(this), 1 );
+ }
+
+ MutexGuard aGuard( m_aMutex );
+ m_xContext = xContext;
+}
+
+Any OServiceManager::getPropertyValue(const OUString& PropertyName)
+{
+ check_undisposed();
+ if ( PropertyName == "DefaultContext" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xContext.is() )
+ return Any( m_xContext );
+ else
+ return Any();
+ }
+ else
+ {
+ UnknownPropertyException except;
+ except.Message = "ServiceManager : unknown property " + PropertyName;
+ throw except;
+ }
+}
+
+void OServiceManager::addPropertyChangeListener(
+ const OUString&, const Reference<XPropertyChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::removePropertyChangeListener(
+ const OUString&, const Reference<XPropertyChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::addVetoableChangeListener(
+ const OUString&, const Reference<XVetoableChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::removeVetoableChangeListener(
+ const OUString&, const Reference<XVetoableChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+// OServiceManager
+Reference<XEventListener > OServiceManager::getFactoryListener()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ if( !xFactoryListener.is() )
+ xFactoryListener = new OServiceManager_Listener( this );
+ return xFactoryListener;
+}
+
+// XMultiServiceFactory, XContentEnumeration
+Sequence< OUString > OServiceManager::getUniqueAvailableServiceNames(
+ HashSet_OWString & aNameSet )
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ for( const auto& rEntry : m_ServiceMap )
+ aNameSet.insert( rEntry.first );
+
+ /* do not return the implementation names
+ HashMap_OWString_Interface m_ImplementationNameMap;
+ HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.begin();
+ while( aIt != m_ImplementationNameMap.end() )
+ aNameSet.insert( (*aIt++).first );
+ */
+
+ return comphelper::containerToSequence(aNameSet);
+}
+
+// XMultiComponentFactory
+Reference< XInterface > OServiceManager::createInstanceWithContext(
+ OUString const & rServiceSpecifier,
+ Reference< XComponentContext > const & xContext )
+{
+ check_undisposed();
+#if OSL_DEBUG_LEVEL > 0
+ Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY );
+ OSL_ASSERT( xProps.is() );
+ if (xProps.is())
+ {
+ Reference< XComponentContext > xDefContext;
+ xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext;
+ OSL_ENSURE(
+ xContext == xDefContext,
+ "### default context of service manager singleton differs from context holding it!" );
+ }
+#endif
+
+ const Sequence< Reference< XInterface > > factories(
+ queryServiceFactories( rServiceSpecifier, xContext ) );
+ for ( Reference< XInterface > const & xFactory : factories )
+ {
+ try
+ {
+ if (xFactory.is())
+ {
+ Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY );
+ if (xFac.is())
+ {
+ return xFac->createInstanceWithContext( xContext );
+ }
+ else
+ {
+ Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY );
+ if (xFac2.is())
+ {
+ SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!");
+ return xFac2->createInstance();
+ }
+ }
+ }
+ }
+ catch (const lang::DisposedException & exc)
+ {
+ SAL_INFO("stoc", "DisposedException occurred: " << exc);
+ }
+ }
+
+ return Reference< XInterface >();
+}
+// XMultiComponentFactory
+Reference< XInterface > OServiceManager::createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext )
+{
+ check_undisposed();
+#if OSL_DEBUG_LEVEL > 0
+ Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY );
+ OSL_ASSERT( xProps.is() );
+ if (xProps.is())
+ {
+ Reference< XComponentContext > xDefContext;
+ xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext;
+ OSL_ENSURE(
+ xContext == xDefContext,
+ "### default context of service manager singleton differs from context holding it!" );
+ }
+#endif
+
+ const Sequence< Reference< XInterface > > factories(
+ queryServiceFactories( rServiceSpecifier, xContext ) );
+ for ( Reference< XInterface > const & xFactory : factories )
+ {
+ try
+ {
+ if (xFactory.is())
+ {
+ Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY );
+ if (xFac.is())
+ {
+ return xFac->createInstanceWithArgumentsAndContext( rArguments, xContext );
+ }
+ else
+ {
+ Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY );
+ if (xFac2.is())
+ {
+ SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!");
+ return xFac2->createInstanceWithArguments( rArguments );
+ }
+ }
+ }
+ }
+ catch (const lang::DisposedException & exc)
+ {
+ SAL_INFO("stoc", "DisposedException occurred: " << exc);
+ }
+ }
+
+ return Reference< XInterface >();
+}
+
+// XMultiServiceFactory, XMultiComponentFactory, XContentEnumeration
+Sequence< OUString > OServiceManager::getAvailableServiceNames()
+{
+ check_undisposed();
+ // all names
+ HashSet_OWString aNameSet;
+ return getUniqueAvailableServiceNames( aNameSet );
+}
+
+// XMultipleServiceFactory
+Reference<XInterface > OServiceManager::createInstance(
+ const OUString& rServiceSpecifier )
+{
+ return createInstanceWithContext(
+ rServiceSpecifier, m_xContext );
+}
+
+// XMultipleServiceFactory
+Reference<XInterface > OServiceManager::createInstanceWithArguments(
+ const OUString& rServiceSpecifier,
+ const Sequence<Any >& rArguments )
+{
+ return createInstanceWithArgumentsAndContext(
+ rServiceSpecifier, rArguments, m_xContext );
+}
+
+// XInitialization
+void OServiceManager::initialize( Sequence< Any > const & )
+{
+ check_undisposed();
+ OSL_FAIL( "not impl!" );
+}
+
+// XServiceInfo
+OUString OServiceManager::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.OServiceManager";
+}
+
+// XServiceInfo
+sal_Bool OServiceManager::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > OServiceManager::getSupportedServiceNames()
+{
+ return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
+}
+
+
+Sequence< Reference< XInterface > > OServiceManager::queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & )
+{
+ Sequence< Reference< XInterface > > ret;
+
+ MutexGuard aGuard( m_aMutex );
+ ::std::pair<
+ HashMultimap_OWString_Interface::iterator,
+ HashMultimap_OWString_Interface::iterator> p(
+ m_ServiceMap.equal_range( aServiceName ) );
+
+ if (p.first == p.second) // no factories
+ {
+ // no service found, look for an implementation
+ HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.find( aServiceName );
+ if( aIt != m_ImplementationNameMap.end() )
+ {
+ Reference< XInterface > const & x = aIt->second;
+ // an implementation found
+ ret = Sequence< Reference< XInterface > >( &x, 1 );
+ }
+ }
+ else
+ {
+ ::std::vector< Reference< XInterface > > vec;
+ vec.reserve( 4 );
+ while (p.first != p.second)
+ {
+ vec.push_back( p.first->second );
+ ++p.first;
+ }
+ ret = Sequence< Reference< XInterface > >( vec.data(), vec.size() );
+ }
+
+ return ret;
+}
+
+// XContentEnumerationAccess
+Reference<XEnumeration > OServiceManager::createContentEnumeration(
+ const OUString& aServiceName )
+{
+ check_undisposed();
+ Sequence< Reference< XInterface > > factories(
+ OServiceManager::queryServiceFactories( aServiceName, m_xContext ) );
+ if (factories.hasElements())
+ return new ServiceEnumeration_Impl( factories );
+ else
+ return Reference< XEnumeration >();
+}
+
+// XEnumeration
+Reference<XEnumeration > OServiceManager::createEnumeration()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ return new ImplementationEnumeration_Impl( m_ImplementationMap );
+}
+
+// XElementAccess
+Type OServiceManager::getElementType()
+{
+ check_undisposed();
+ return cppu::UnoType<XInterface>::get();
+}
+
+// XElementAccess
+sal_Bool OServiceManager::hasElements()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ return !m_ImplementationMap.empty();
+}
+
+// XSet
+sal_Bool OServiceManager::has( const Any & Element )
+{
+ check_undisposed();
+ if( Element.getValueTypeClass() == TypeClass_INTERFACE )
+ {
+ Reference<XInterface > xEle( Element, UNO_QUERY_THROW );
+ MutexGuard aGuard( m_aMutex );
+ return m_ImplementationMap.find( xEle ) !=
+ m_ImplementationMap.end();
+ }
+ else if (auto implName = o3tl::tryAccess<OUString>(Element))
+ {
+ MutexGuard aGuard( m_aMutex );
+ return m_ImplementationNameMap.find( *implName ) !=
+ m_ImplementationNameMap.end();
+ }
+ return false;
+}
+
+// XSet
+void OServiceManager::insert( const Any & Element )
+{
+ check_undisposed();
+ if( Element.getValueTypeClass() != TypeClass_INTERFACE )
+ {
+ throw IllegalArgumentException(
+ "exception interface, got " + Element.getValueType().getTypeName(),
+ Reference< XInterface >(), 0 );
+ }
+ Reference<XInterface > xEle( Element, UNO_QUERY_THROW );
+
+ {
+ MutexGuard aGuard( m_aMutex );
+ HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle );
+ if( aIt != m_ImplementationMap.end() )
+ {
+ throw ElementExistException( "element already exists!" );
+ }
+
+ // put into the implementation hashmap
+ m_ImplementationMap.insert( xEle );
+
+ // put into the implementation name hashmap
+ Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) );
+ if( xInfo.is() )
+ {
+ OUString aImplName = xInfo->getImplementationName();
+ if( !aImplName.isEmpty() )
+ m_ImplementationNameMap[ aImplName ] = xEle;
+
+ //put into the service map
+ const Sequence< OUString > aServiceNames = xInfo->getSupportedServiceNames();
+ for( const OUString& rServiceName : aServiceNames )
+ {
+ m_ServiceMap.emplace(
+ rServiceName, *o3tl::doAccess<Reference<XInterface>>(Element) );
+ }
+ }
+ }
+ // add the disposing listener to the factory
+ Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) );
+ if( xComp.is() )
+ xComp->addEventListener( getFactoryListener() );
+}
+
+// helper function
+bool OServiceManager::haveFactoryWithThisImplementation(const OUString& aImplName)
+{
+ return ( m_ImplementationNameMap.find(aImplName) != m_ImplementationNameMap.end());
+}
+
+// XSet
+void OServiceManager::remove( const Any & Element )
+{
+ if (is_disposed())
+ return;
+
+ Reference<XInterface > xEle;
+ if (Element.getValueTypeClass() == TypeClass_INTERFACE)
+ {
+ xEle.set( Element, UNO_QUERY_THROW );
+ }
+ else if (auto implName = o3tl::tryAccess<OUString>(Element))
+ {
+ MutexGuard aGuard( m_aMutex );
+ HashMap_OWString_Interface::const_iterator const iFind(
+ m_ImplementationNameMap.find( *implName ) );
+ if (iFind == m_ImplementationNameMap.end())
+ {
+ throw NoSuchElementException(
+ "element is not in: " + *implName,
+ static_cast< OWeakObject * >(this) );
+ }
+ xEle = iFind->second;
+ }
+ else
+ {
+ throw IllegalArgumentException(
+ "expected interface or string, got " + Element.getValueType().getTypeName(),
+ Reference< XInterface >(), 0 );
+ }
+
+ // remove the disposing listener from the factory
+ Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) );
+ if( xComp.is() )
+ xComp->removeEventListener( getFactoryListener() );
+
+ MutexGuard aGuard( m_aMutex );
+ HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle );
+ if( aIt == m_ImplementationMap.end() )
+ {
+ throw NoSuchElementException(
+ "element not found",
+ static_cast< OWeakObject * >(this) );
+ }
+ //First remove all factories which have been loaded by ORegistryServiceManager.
+ m_SetLoadedFactories.erase( *aIt);
+ //Remove from the implementation map. It contains all factories of m_SetLoadedFactories
+ //which have been added directly through XSet, that is not via ORegistryServiceManager
+ m_ImplementationMap.erase( aIt );
+
+ // remove from the implementation name hashmap
+ Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) );
+ if( xInfo.is() )
+ {
+ OUString aImplName = xInfo->getImplementationName();
+ if( !aImplName.isEmpty() )
+ m_ImplementationNameMap.erase( aImplName );
+ }
+
+ //remove from the service map
+ Reference<XServiceInfo > xSF( Reference<XServiceInfo >::query( xEle ) );
+ if( !xSF.is() )
+ return;
+
+ const Sequence< OUString > aServiceNames = xSF->getSupportedServiceNames();
+ for( const OUString& rServiceName : aServiceNames )
+ {
+ std::pair<HashMultimap_OWString_Interface::iterator, HashMultimap_OWString_Interface::iterator> p =
+ m_ServiceMap.equal_range( rServiceName );
+
+ while( p.first != p.second )
+ {
+ if( xEle == (*p.first).second )
+ {
+ m_ServiceMap.erase( p.first );
+ break;
+ }
+ ++p.first;
+ }
+ }
+}
+
+/*****************************************************************************
+ class ORegistryServiceManager
+*****************************************************************************/
+class ORegistryServiceManager : public OServiceManager
+{
+public:
+ explicit ORegistryServiceManager( Reference< XComponentContext > const & xContext );
+
+ // XInitialization
+ void SAL_CALL initialize(const Sequence< Any >& Arguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.ORegistryServiceManager"; }
+
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XMultiServiceFactory
+ Sequence< OUString > SAL_CALL getAvailableServiceNames() override;
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override;
+
+ // XComponent
+ void SAL_CALL dispose() override;
+
+ // OServiceManager
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+
+protected:
+ //OServiceManager
+ Sequence< Reference< XInterface > > queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext ) override;
+private:
+ Reference<XRegistryKey > getRootKey();
+ Reference<XInterface > loadWithImplementationName(
+ const OUString & rImplName, Reference< XComponentContext > const & xContext );
+ Sequence<OUString> getFromServiceName(std::u16string_view serviceName) const;
+ Reference<XInterface > loadWithServiceName(
+ std::u16string_view rImplName, Reference< XComponentContext > const & xContext );
+ void fillAllNamesFromRegistry( HashSet_OWString & );
+
+ bool m_searchedRegistry;
+ Reference<XSimpleRegistry > m_xRegistry; // readonly property Registry
+ Reference<XRegistryKey > m_xRootKey;
+
+#if OSL_DEBUG_LEVEL > 0
+ bool m_init;
+#endif
+};
+
+/**
+ * Create a ServiceManager
+ */
+ORegistryServiceManager::ORegistryServiceManager( Reference< XComponentContext > const & xContext )
+ : OServiceManager( xContext )
+ , m_searchedRegistry(false)
+#if OSL_DEBUG_LEVEL > 0
+ , m_init( false )
+#endif
+{
+}
+
+// XComponent
+void ORegistryServiceManager::dispose()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ return;
+ OServiceManager::dispose();
+ // dispose
+ MutexGuard aGuard( m_aMutex );
+ // erase all members
+ m_xRegistry.clear();
+ m_xRootKey.clear();
+}
+
+/**
+ * Return the root key of the registry. The Default registry service is ordered
+ * if no registry is set.
+ */
+//Reference<XServiceProvider > create_DefaultRegistry_ServiceProvider();
+
+Reference<XRegistryKey > ORegistryServiceManager::getRootKey()
+{
+ if( !m_xRootKey.is() )
+ {
+ MutexGuard aGuard( m_aMutex );
+ // DefaultRegistry suchen !!!!
+ if( !m_xRegistry.is() && !m_searchedRegistry )
+ {
+ // NB. we only search this once
+ m_searchedRegistry = true;
+
+ m_xRegistry.set(
+ createInstanceWithContext(
+ "com.sun.star.registry.DefaultRegistry",
+ m_xContext ),
+ UNO_QUERY );
+ }
+ if( m_xRegistry.is() && !m_xRootKey.is() )
+ m_xRootKey = m_xRegistry->getRootKey();
+ }
+
+ return m_xRootKey;
+}
+
+/**
+ * Create a service provider from the registry with an implementation name
+ */
+Reference<XInterface > ORegistryServiceManager::loadWithImplementationName(
+ const OUString& name, Reference< XComponentContext > const & xContext )
+{
+ Reference<XInterface > ret;
+
+ Reference<XRegistryKey > xRootKey = getRootKey();
+ if( !xRootKey.is() )
+ return ret;
+
+ try
+ {
+ OUString implementationName = "/IMPLEMENTATIONS/" + name;
+ Reference<XRegistryKey > xImpKey = m_xRootKey->openKey(implementationName);
+
+ if( xImpKey.is() )
+ {
+ Reference< lang::XMultiServiceFactory > xMgr;
+ if (xContext.is())
+ xMgr.set( xContext->getServiceManager(), UNO_QUERY_THROW );
+ else
+ xMgr.set( this );
+ ret = createSingleRegistryFactory( xMgr, name, xImpKey );
+ insert( Any( ret ) );
+ // Remember this factory as loaded in contrast to inserted ( XSet::insert)
+ // factories. Those loaded factories in this set are candidates for being
+ // released on an unloading notification.
+ m_SetLoadedFactories.insert( ret);
+ }
+ }
+ catch (InvalidRegistryException &)
+ {
+ }
+
+ return ret;
+}
+
+/**
+ * Return all implementation out of the registry.
+ */
+Sequence<OUString> ORegistryServiceManager::getFromServiceName(
+ std::u16string_view serviceName ) const
+{
+ OUString buf = OUString::Concat("/SERVICES/") + serviceName;
+ return retrieveAsciiValueList( m_xRegistry, buf );
+}
+
+/**
+ * Create a service provider from the registry
+ */
+Reference<XInterface > ORegistryServiceManager::loadWithServiceName(
+ std::u16string_view serviceName, Reference< XComponentContext > const & xContext )
+{
+ const Sequence<OUString> implEntries = getFromServiceName( serviceName );
+ for (const auto& rEntry : implEntries)
+ {
+ Reference< XInterface > x( loadWithImplementationName( rEntry, xContext ) );
+ if (x.is())
+ return x;
+ }
+
+ return Reference<XInterface >();
+}
+
+/**
+ * Return a sequence of all service names from the registry.
+ */
+void ORegistryServiceManager::fillAllNamesFromRegistry( HashSet_OWString & rSet )
+{
+ Reference<XRegistryKey > xRootKey = getRootKey();
+ if( !xRootKey.is() )
+ return;
+
+ try
+ {
+ Reference<XRegistryKey > xServicesKey = xRootKey->openKey( "SERVICES" );
+ // root + /Services + /
+ if( xServicesKey.is() )
+ {
+ sal_Int32 nPrefix = xServicesKey->getKeyName().getLength() +1;
+ const Sequence<Reference<XRegistryKey > > aKeys = xServicesKey->openKeys();
+ std::transform(aKeys.begin(), aKeys.end(), std::inserter(rSet, rSet.end()),
+ [nPrefix](const Reference<XRegistryKey>& rKey) -> OUString {
+ return rKey->getKeyName().copy( nPrefix ); });
+ }
+ }
+ catch (InvalidRegistryException &)
+ {
+ }
+}
+
+// XInitialization
+void ORegistryServiceManager::initialize(const Sequence< Any >& Arguments)
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ if (Arguments.hasElements())
+ {
+ m_xRootKey.clear();
+ Arguments[ 0 ] >>= m_xRegistry;
+ }
+#if OSL_DEBUG_LEVEL > 0
+ // to find all bootstrapping processes to be fixed...
+ OSL_ENSURE( !m_init, "### second init of service manager instance!" );
+ m_init = true;
+#endif
+}
+
+// XMultiServiceFactory, XContentEnumeration
+Sequence< OUString > ORegistryServiceManager::getAvailableServiceNames()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ // all names
+ HashSet_OWString aNameSet;
+
+ // all names from the registry
+ fillAllNamesFromRegistry( aNameSet );
+
+ return OServiceManager::getUniqueAvailableServiceNames( aNameSet );
+}
+
+// XServiceInfo
+Sequence< OUString > ORegistryServiceManager::getSupportedServiceNames()
+{
+ return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.RegistryServiceManager" };
+}
+
+
+// OServiceManager
+Sequence< Reference< XInterface > > ORegistryServiceManager::queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext )
+{
+ Sequence< Reference< XInterface > > ret(
+ OServiceManager::queryServiceFactories( aServiceName, xContext ) );
+ if (ret.hasElements())
+ {
+ return ret;
+ }
+ else
+ {
+ MutexGuard aGuard( m_aMutex );
+ Reference< XInterface > x( loadWithServiceName( aServiceName, xContext ) );
+ if (! x.is())
+ x = loadWithImplementationName( aServiceName, xContext );
+ return Sequence< Reference< XInterface > >( &x, 1 );
+ }
+}
+
+// XContentEnumerationAccess
+Reference<XEnumeration > ORegistryServiceManager::createContentEnumeration(
+ const OUString& aServiceName )
+{
+ check_undisposed();
+ MutexGuard aGuard(m_aMutex);
+ // get all implementation names registered under this service name from the registry
+ const Sequence<OUString> aImpls = getFromServiceName( aServiceName );
+ // load and insert all factories specified by the registry
+ for( const OUString& aImplName : aImpls )
+ {
+ if ( !haveFactoryWithThisImplementation(aImplName) )
+ {
+ loadWithImplementationName( aImplName, m_xContext );
+ }
+ }
+ // call the superclass to enumerate all contents
+ return OServiceManager::createContentEnumeration( aServiceName );
+}
+
+// OServiceManager
+Reference<XPropertySetInfo > ORegistryServiceManager::getPropertySetInfo()
+{
+ check_undisposed();
+ if (! m_xPropertyInfo.is())
+ {
+ Sequence< beans::Property > seq{
+ beans::Property("DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0),
+ beans::Property("Registry", -1, cppu::UnoType<decltype(m_xRegistry)>::get(),
+ beans::PropertyAttribute::READONLY)
+ };
+ Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) );
+
+ MutexGuard aGuard( m_aMutex );
+ if (! m_xPropertyInfo.is())
+ {
+ m_xPropertyInfo = xInfo;
+ }
+ }
+ return m_xPropertyInfo;
+}
+
+Any ORegistryServiceManager::getPropertyValue(const OUString& PropertyName)
+{
+ check_undisposed();
+ if ( PropertyName == "Registry" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xRegistry.is() )
+ return Any( m_xRegistry );
+ else
+ return Any();
+ }
+ return OServiceManager::getPropertyValue( PropertyName );
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_OServiceManager_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OServiceManager(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_ORegistryServiceManager_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ORegistryServiceManager(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_OServiceManagerWrapper_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OServiceManagerWrapper(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/simpleregistry/simpleregistry.cxx b/stoc/source/simpleregistry/simpleregistry.cxx
new file mode 100644
index 000000000..6291889a3
--- /dev/null
+++ b/stoc/source/simpleregistry/simpleregistry.cxx
@@ -0,0 +1,941 @@
+/* -*- 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 <sal/config.h>
+
+#include <cstdlib>
+#include <mutex>
+#include <vector>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/registry/InvalidValueException.hpp>
+#include <com/sun/star/registry/MergeConflictException.hpp>
+#include <com/sun/star/registry/RegistryKeyType.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <registry/registry.hxx>
+#include <registry/regtype.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace {
+
+class SimpleRegistry:
+ public cppu::WeakImplHelper<
+ css::registry::XSimpleRegistry, css::lang::XServiceInfo >
+{
+public:
+ SimpleRegistry() {}
+
+ std::mutex mutex_;
+
+private:
+ virtual OUString SAL_CALL getURL() override;
+
+ virtual void SAL_CALL open(
+ OUString const & rURL, sal_Bool bReadOnly, sal_Bool bCreate) override;
+
+ virtual sal_Bool SAL_CALL isValid() override;
+
+ virtual void SAL_CALL close() override;
+
+ virtual void SAL_CALL destroy() override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL
+ getRootKey() override;
+
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+
+ virtual void SAL_CALL mergeKey(
+ OUString const & aKeyName, OUString const & aUrl) override;
+
+ virtual OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.SimpleRegistry"; }
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override
+ {
+ css::uno::Sequence< OUString > names { "com.sun.star.registry.SimpleRegistry" };
+ return names;
+ }
+
+ Registry registry_;
+};
+
+class Key: public cppu::WeakImplHelper< css::registry::XRegistryKey > {
+public:
+ Key(
+ rtl::Reference< SimpleRegistry > const & registry,
+ RegistryKey const & key):
+ registry_(registry), key_(key) {}
+
+private:
+ virtual OUString SAL_CALL getKeyName() override;
+
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+
+ virtual sal_Bool SAL_CALL isValid() override;
+
+ virtual css::registry::RegistryKeyType SAL_CALL getKeyType(
+ OUString const & rKeyName) override;
+
+ virtual css::registry::RegistryValueType SAL_CALL getValueType() override;
+
+ virtual sal_Int32 SAL_CALL getLongValue() override;
+
+ virtual void SAL_CALL setLongValue(sal_Int32 value) override;
+
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getLongListValue() override;
+
+ virtual void SAL_CALL setLongListValue(
+ css::uno::Sequence< sal_Int32 > const & seqValue) override;
+
+ virtual OUString SAL_CALL getAsciiValue() override;
+
+ virtual void SAL_CALL setAsciiValue(OUString const & value) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getAsciiListValue() override;
+
+ virtual void SAL_CALL setAsciiListValue(
+ css::uno::Sequence< OUString > const & seqValue) override;
+
+ virtual OUString SAL_CALL getStringValue() override;
+
+ virtual void SAL_CALL setStringValue(OUString const & value) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getStringListValue() override;
+
+ virtual void SAL_CALL setStringListValue(
+ css::uno::Sequence< OUString > const & seqValue) override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBinaryValue() override;
+
+ virtual void SAL_CALL setBinaryValue(
+ css::uno::Sequence< sal_Int8 > const & value) override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL openKey(
+ OUString const & aKeyName) override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL
+ createKey(OUString const & aKeyName) override;
+
+ virtual void SAL_CALL closeKey() override;
+
+ virtual void SAL_CALL deleteKey(OUString const & rKeyName) override;
+
+ virtual
+ css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+ SAL_CALL openKeys() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getKeyNames() override;
+
+ virtual sal_Bool SAL_CALL createLink(
+ OUString const & aLinkName, OUString const & aLinkTarget) override;
+
+ virtual void SAL_CALL deleteLink(OUString const & rLinkName) override;
+
+ virtual OUString SAL_CALL getLinkTarget(OUString const & rLinkName) override;
+
+ virtual OUString SAL_CALL getResolvedName(OUString const & aKeyName) override;
+
+ rtl::Reference< SimpleRegistry > registry_;
+ RegistryKey key_;
+};
+
+OUString Key::getKeyName() {
+ std::scoped_lock guard(registry_->mutex_);
+ return key_.getName();
+}
+
+sal_Bool Key::isReadOnly()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ return key_.isReadOnly();
+}
+
+sal_Bool Key::isValid() {
+ std::scoped_lock guard(registry_->mutex_);
+ return key_.isValid();
+}
+
+css::registry::RegistryKeyType Key::getKeyType(OUString const & )
+{
+ return css::registry::RegistryKeyType_KEY;
+}
+
+css::registry::RegistryValueType Key::getValueType()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_.getValueInfo(OUString(), &type, &size);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::INVALID_VALUE:
+ type = RegValueType::NOT_DEFINED;
+ break;
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getValueType:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ switch (type) {
+ default:
+ std::abort(); // this cannot happen
+ // pseudo-fall-through to avoid warnings on MSC
+ case RegValueType::NOT_DEFINED:
+ return css::registry::RegistryValueType_NOT_DEFINED;
+ case RegValueType::LONG:
+ return css::registry::RegistryValueType_LONG;
+ case RegValueType::STRING:
+ return css::registry::RegistryValueType_ASCII;
+ case RegValueType::UNICODE:
+ return css::registry::RegistryValueType_STRING;
+ case RegValueType::BINARY:
+ return css::registry::RegistryValueType_BINARY;
+ case RegValueType::LONGLIST:
+ return css::registry::RegistryValueType_LONGLIST;
+ case RegValueType::STRINGLIST:
+ return css::registry::RegistryValueType_ASCIILIST;
+ case RegValueType::UNICODELIST:
+ return css::registry::RegistryValueType_STRINGLIST;
+ }
+}
+
+sal_Int32 Key::getLongValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ sal_Int32 value;
+ RegError err = key_.getValue(OUString(), &value);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongValue:"
+ " underlying RegistryKey::getValue() = RegError::INVALID_VALUE",
+ static_cast< OWeakObject * >(this));
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLongValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ return value;
+}
+
+void Key::setLongValue(sal_Int32 value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.setValue(
+ OUString(), RegValueType::LONG, &value, sizeof (sal_Int32));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setLongValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Sequence< sal_Int32 > Key::getLongListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< sal_Int32 > list;
+ RegError err = key_.getLongListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< sal_Int32 >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() ="
+ " RegError::INVALID_VALUE",
+ static_cast< OWeakObject * >(this));
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< sal_Int32 > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aValueRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return value;
+}
+
+void Key::setLongListValue(css::uno::Sequence< sal_Int32 > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.setLongListValue(
+ OUString(), seqValue.getConstArray(), static_cast< sal_uInt32 >(seqValue.getLength()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setLongListValue:"
+ " underlying RegistryKey::setLongListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+OUString Key::getAsciiValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_.getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (type != RegValueType::STRING) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ static_cast< OWeakObject * >(this));
+ }
+ // size contains terminating null (error in underlying registry.cxx):
+ if (size == 0) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey size 0 cannot happen due to"
+ " design error",
+ static_cast< OWeakObject * >(this));
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey size too large",
+ static_cast< OWeakObject * >(this));
+ }
+ std::vector< char > list(size);
+ err = key_.getValue(OUString(), list.data());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (list[size - 1] != '\0') {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey value must be null-terminated due"
+ " to design error",
+ static_cast< OWeakObject * >(this));
+ }
+ OUString value;
+ if (!rtl_convertStringToUString(
+ &value.pData, list.data(),
+ static_cast< sal_Int32 >(size - 1), RTL_TEXTENCODING_UTF8,
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey not UTF-8",
+ static_cast< OWeakObject * >(this));
+ }
+ return value;
+}
+
+void Key::setAsciiValue(OUString const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ OString utf8;
+ if (!value.convertToString(
+ &utf8, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ throw css::uno::RuntimeException(
+ "com.sun.star.registry.SimpleRegistry key setAsciiValue:"
+ " value not UTF-16",
+ static_cast< OWeakObject * >(this));
+ }
+ RegError err = key_.setValue(
+ OUString(), RegValueType::STRING,
+ const_cast< char * >(utf8.getStr()), utf8.getLength() + 1);
+ // +1 for terminating null (error in underlying registry.cxx)
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setAsciiValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Sequence< OUString > Key::getAsciiListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< char * > list;
+ RegError err = key_.getStringListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< OUString >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() = RegError::INVALID_VALUE",
+ static_cast< OWeakObject * >(this));
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< OUString > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ char * el = list.getElement(i);
+ sal_Int32 size = rtl_str_getLength(el);
+ if (!rtl_convertStringToUString(
+ &aValueRange[static_cast< sal_Int32 >(i)].pData, el, size,
+ RTL_TEXTENCODING_UTF8,
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying RegistryKey not"
+ " UTF-8",
+ static_cast< OWeakObject * >(this));
+ }
+ }
+ return value;
+}
+
+void Key::setAsciiListValue(
+ css::uno::Sequence< OUString > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ std::vector< OString > list;
+ for (const auto& rValue : seqValue) {
+ OString utf8;
+ if (!rValue.convertToString(
+ &utf8, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ throw css::uno::RuntimeException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setAsciiListValue: value not UTF-16",
+ static_cast< OWeakObject * >(this));
+ }
+ list.push_back(utf8);
+ }
+ std::vector< char * > list2;
+ for (const auto& rItem : list)
+ {
+ list2.push_back(const_cast< char * >(rItem.getStr()));
+ }
+ RegError err = key_.setStringListValue(
+ OUString(), list2.data(), static_cast< sal_uInt32 >(list2.size()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setAsciiListValue: underlying"
+ " RegistryKey::setStringListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+OUString Key::getStringValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_.getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (type != RegValueType::UNICODE) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ static_cast< OWeakObject * >(this));
+ }
+ // size contains terminating null and is *2 (error in underlying
+ // registry.cxx):
+ if (size == 0 || (size & 1) == 1) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey size 0 or odd cannot happen due to"
+ " design error",
+ static_cast< OWeakObject * >(this));
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey size too large",
+ static_cast< OWeakObject * >(this));
+ }
+ std::vector< sal_Unicode > list(size);
+ err = key_.getValue(OUString(), list.data());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (list[size/2 - 1] != 0) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey value must be null-terminated due"
+ " to design error",
+ static_cast< OWeakObject * >(this));
+ }
+ return OUString(list.data(), static_cast< sal_Int32 >(size/2 - 1));
+}
+
+void Key::setStringValue(OUString const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.setValue(
+ OUString(), RegValueType::UNICODE,
+ const_cast< sal_Unicode * >(value.getStr()),
+ (value.getLength() + 1) * sizeof (sal_Unicode));
+ // +1 for terminating null (error in underlying registry.cxx)
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setStringValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Sequence< OUString > Key::getStringListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< sal_Unicode * > list;
+ RegError err = key_.getUnicodeListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< OUString >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() = RegError::INVALID_VALUE",
+ static_cast< OWeakObject * >(this));
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< OUString > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aValueRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return value;
+}
+
+void Key::setStringListValue(
+ css::uno::Sequence< OUString > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ std::vector< sal_Unicode * > list;
+ list.reserve(seqValue.getLength());
+ std::transform(seqValue.begin(), seqValue.end(), std::back_inserter(list),
+ [](const OUString& rValue) -> sal_Unicode* { return const_cast<sal_Unicode*>(rValue.getStr()); });
+ RegError err = key_.setUnicodeListValue(
+ OUString(), list.data(), static_cast< sal_uInt32 >(list.size()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setStringListValue: underlying"
+ " RegistryKey::setUnicodeListValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Sequence< sal_Int8 > Key::getBinaryValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_.getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (type != RegValueType::BINARY) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ static_cast< OWeakObject * >(this));
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey size too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< sal_Int8 > value(static_cast< sal_Int32 >(size));
+ err = key_.getValue(OUString(), value.getArray());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ return value;
+}
+
+void Key::setBinaryValue(css::uno::Sequence< sal_Int8 > const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.setValue(
+ OUString(), RegValueType::BINARY,
+ const_cast< sal_Int8 * >(value.getConstArray()),
+ static_cast< sal_uInt32 >(value.getLength()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setBinaryValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > Key::openKey(
+ OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKey key;
+ RegError err = key_.openKey(aKeyName, key);
+ switch (err) {
+ case RegError::NO_ERROR:
+ return new Key(registry_, key);
+ case RegError::KEY_NOT_EXISTS:
+ return css::uno::Reference< css::registry::XRegistryKey >();
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key openKey:"
+ " underlying RegistryKey::openKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > Key::createKey(
+ OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKey key;
+ RegError err = key_.createKey(aKeyName, key);
+ switch (err) {
+ case RegError::NO_ERROR:
+ return new Key(registry_, key);
+ case RegError::INVALID_KEYNAME:
+ return css::uno::Reference< css::registry::XRegistryKey >();
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key createKey:"
+ " underlying RegistryKey::createKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+void Key::closeKey()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.closeKey();
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key closeKey:"
+ " underlying RegistryKey::closeKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+void Key::deleteKey(OUString const & rKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_.deleteKey(rKeyName);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key deleteKey:"
+ " underlying RegistryKey::deleteKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+Key::openKeys()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKeyArray list;
+ RegError err = key_.openSubKeys(OUString(), list);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key openKeys:"
+ " underlying RegistryKey::openSubKeys() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+ keys(static_cast< sal_Int32 >(n));
+ auto aKeysRange = asNonConstRange(keys);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aKeysRange[static_cast< sal_Int32 >(i)] = new Key(
+ registry_, list.getElement(i));
+ }
+ return keys;
+}
+
+css::uno::Sequence< OUString > Key::getKeyNames()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKeyNames list;
+ RegError err = key_.getKeyNames(OUString(), list);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() too large",
+ static_cast< OWeakObject * >(this));
+ }
+ css::uno::Sequence< OUString > names(static_cast< sal_Int32 >(n));
+ auto aNamesRange = asNonConstRange(names);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aNamesRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return names;
+}
+
+sal_Bool Key::createLink(
+ OUString const & /*aLinkName*/, OUString const & /*aLinkTarget*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key createLink: links are no longer supported",
+ static_cast< OWeakObject * >(this));
+}
+
+void Key::deleteLink(OUString const & /*rLinkName*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key deleteLink: links are no longer supported",
+ static_cast< OWeakObject * >(this));
+}
+
+OUString Key::getLinkTarget(OUString const & /*rLinkName*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLinkTarget: links are no longer supported",
+ static_cast< OWeakObject * >(this));
+}
+
+OUString Key::getResolvedName(OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ OUString resolved;
+ RegError err = key_.getResolvedKeyName(aKeyName, resolved);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getResolvedName:"
+ " underlying RegistryKey::getResolvedName() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ return resolved;
+}
+
+OUString SimpleRegistry::getURL() {
+ std::scoped_lock guard(mutex_);
+ return registry_.getName();
+}
+
+void SimpleRegistry::open(
+ OUString const & rURL, sal_Bool bReadOnly, sal_Bool bCreate)
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = (rURL.isEmpty() && bCreate)
+ ? RegError::REGISTRY_NOT_EXISTS
+ : registry_.open(rURL, bReadOnly ? RegAccessMode::READONLY : RegAccessMode::READWRITE);
+ if (err == RegError::REGISTRY_NOT_EXISTS && bCreate) {
+ err = registry_.create(rURL);
+ }
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.open(" + rURL +
+ "): underlying Registry::open/create() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+sal_Bool SimpleRegistry::isValid() {
+ std::scoped_lock guard(mutex_);
+ return registry_.isValid();
+}
+
+void SimpleRegistry::close()
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = registry_.close();
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.close:"
+ " underlying Registry::close() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+void SimpleRegistry::destroy()
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = registry_.destroy(OUString());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.destroy:"
+ " underlying Registry::destroy() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > SimpleRegistry::getRootKey()
+{
+ std::scoped_lock guard(mutex_);
+ RegistryKey root;
+ RegError err = registry_.openRootKey(root);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.getRootKey:"
+ " underlying Registry::getRootKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+ return new Key(this, root);
+}
+
+sal_Bool SimpleRegistry::isReadOnly()
+{
+ std::scoped_lock guard(mutex_);
+ return registry_.isReadOnly();
+}
+
+void SimpleRegistry::mergeKey(
+ OUString const & aKeyName, OUString const & aUrl)
+{
+ std::scoped_lock guard(mutex_);
+ RegistryKey root;
+ RegError err = registry_.openRootKey(root);
+ if (err == RegError::NO_ERROR) {
+ err = registry_.mergeKey(root, aKeyName, aUrl, false);
+ }
+ switch (err) {
+ case RegError::NO_ERROR:
+ case RegError::MERGE_CONFLICT:
+ break;
+ case RegError::MERGE_ERROR:
+ throw css::registry::MergeConflictException(
+ "com.sun.star.registry.SimpleRegistry.mergeKey:"
+ " underlying Registry::mergeKey() = RegError::MERGE_ERROR",
+ static_cast< cppu::OWeakObject * >(this));
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.mergeKey:"
+ " underlying Registry::getRootKey/mergeKey() = " + OUString::number(static_cast<int>(err)),
+ static_cast< OWeakObject * >(this));
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_SimpleRegistry_get_implementation(
+ SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SimpleRegistry);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/typeconv/convert.cxx b/stoc/source/typeconv/convert.cxx
new file mode 100644
index 000000000..1b50c9449
--- /dev/null
+++ b/stoc/source/typeconv/convert.cxx
@@ -0,0 +1,870 @@
+/* -*- 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 <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+
+#ifdef _WIN32
+#include <cmath>
+#else
+#include <math.h>
+#endif
+#include <float.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/FailReason.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::script;
+using namespace cppu;
+using namespace osl;
+
+namespace stoc_tcv
+{
+
+static double round( double aVal )
+{
+ bool bPos = (aVal >= 0.0);
+ aVal = ::fabs( aVal );
+ double aUpper = ::ceil( aVal );
+
+ aVal = ((aUpper-aVal) <= 0.5) ? aUpper : (aUpper - 1.0);
+ return (bPos ? aVal : -aVal);
+}
+
+
+static bool getNumericValue( double & rfVal, const OUString & rStr )
+{
+ double fRet = rStr.toDouble();
+ if (fRet == 0.0)
+ {
+ sal_Int32 nLen = rStr.getLength();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rfVal = 0.0;
+ return true;
+ }
+
+ OUString trim( rStr.trim() );
+
+ // try hex
+ sal_Int32 nX = trim.indexOf( 'x' );
+ if (nX < 0)
+ nX = trim.indexOf( 'X' );
+
+ if (nX > 0 && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.copy( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rfVal = (bNeg ? -static_cast<double>(nRet) : static_cast<double>(nRet));
+ return true;
+ }
+
+ nLen = trim.getLength();
+ sal_Int32 nPos = 0;
+
+ // skip +/-
+ if (nLen && (trim[0] == '-' || trim[0] == '+'))
+ ++nPos;
+
+ while (nPos < nLen) // skip leading zeros
+ {
+ if (trim[nPos] != '0')
+ {
+ if (trim[nPos] != '.')
+ return false;
+ ++nPos;
+ while (nPos < nLen) // skip trailing zeros
+ {
+ if (trim[nPos] != '0')
+ return false;
+ ++nPos;
+ }
+ break;
+ }
+ ++nPos;
+ }
+ }
+ rfVal = fRet;
+ return true;
+}
+
+
+static bool getHyperValue( sal_Int64 & rnVal, const OUString & rStr )
+{
+ sal_Int32 nLen = rStr.getLength();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rnVal = 0;
+ return true;
+ }
+
+ OUString trim( rStr.trim() );
+
+ // try hex
+ sal_Int32 nX = trim.indexOf( 'x' );
+ if (nX < 0)
+ nX = trim.indexOf( 'X' );
+
+ if (nX >= 0)
+ {
+ if (nX > 0 && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.copy( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rnVal = (bNeg ? -static_cast<sal_Int64>(nRet) : nRet);
+ return true;
+ }
+ return false;
+ }
+
+ double fVal;
+ if (getNumericValue( fVal, rStr ) &&
+ fVal >= double(SAL_MIN_INT64) &&
+ fVal <= double(SAL_MAX_UINT64))
+ {
+ rnVal = static_cast<sal_Int64>(round( fVal ));
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class TypeConverter_Impl : public WeakImplHelper< XTypeConverter, XServiceInfo >
+{
+ // ...misc helpers...
+ /// @throws CannotConvertException
+ static sal_Int64 toHyper(
+ const Any& rAny, sal_Int64 min, sal_uInt64 max = SAL_MAX_UINT64 );
+ /// @throws CannotConvertException
+ static double toDouble( const Any& rAny, double min = -DBL_MAX, double max = DBL_MAX );
+
+public:
+ TypeConverter_Impl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeConverter
+ virtual Any SAL_CALL convertTo( const Any& aFrom, const Type& DestinationType ) override;
+ virtual Any SAL_CALL convertToSimpleType( const Any& aFrom, TypeClass aDestinationType ) override;
+};
+
+}
+
+TypeConverter_Impl::TypeConverter_Impl() {}
+
+// XServiceInfo
+OUString TypeConverter_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.TypeConverter";
+}
+
+// XServiceInfo
+sal_Bool TypeConverter_Impl::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > TypeConverter_Impl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.Converter" };
+}
+
+
+sal_Int64 TypeConverter_Impl::toHyper( const Any& rAny, sal_Int64 min, sal_uInt64 max )
+{
+ sal_Int64 nRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ nRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ nRet = *o3tl::forceAccess<bool>(rAny) ? 1 : 0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ nRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ nRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ nRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ nRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ nRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ nRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ nRet = *o3tl::forceAccess<sal_Int64>(rAny);
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ auto const n = *o3tl::forceAccess<sal_uInt64>(rAny);
+ if ((min < 0 || n >= o3tl::make_unsigned(min)) && // lower bound
+ n <= max) // upper bound
+ {
+ return static_cast<sal_Int64>(n);
+ }
+ throw CannotConvertException(
+ "UNSIGNED HYPER out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ {
+ double fVal = round( *o3tl::forceAccess<float>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "FLOAT out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+ case TypeClass_DOUBLE:
+ {
+ double fVal = round( *o3tl::forceAccess<double>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "DOUBLE out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ sal_Int64 nVal = SAL_CONST_INT64(0);
+ if (! getHyperValue( nVal, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ nRet = nVal;
+ if (nVal >= min && (nVal < 0 || o3tl::make_unsigned(nVal) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "STRING value out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ default:
+ throw CannotConvertException(
+ "TYPE is not supported!",
+ Reference<XInterface>(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (nRet >= min && (nRet < 0 || o3tl::make_unsigned(nRet) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+double TypeConverter_Impl::toDouble( const Any& rAny, double min, double max )
+{
+ double fRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ fRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ fRet = *o3tl::forceAccess<bool>(rAny) ? 1.0 : 0.0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ fRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ fRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ fRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ fRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ fRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ fRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_Int64>(rAny));
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_uInt64>(rAny));
+ break;
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ fRet = *o3tl::forceAccess<float>(rAny);
+ break;
+ case TypeClass_DOUBLE:
+ fRet = *o3tl::forceAccess<double>(rAny);
+ break;
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ if (! getNumericValue( fRet, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ break;
+ }
+
+ default:
+ throw CannotConvertException(
+ "TYPE is not supported!",
+ Reference< XInterface >(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (fRet >= min && fRet <= max)
+ return fRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference< XInterface >(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+Any SAL_CALL TypeConverter_Impl::convertTo( const Any& rVal, const Type& aDestType )
+{
+ const Type& aSourceType = rVal.getValueType();
+ if (aSourceType == aDestType)
+ return rVal;
+
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ TypeClass aDestinationClass = aDestType.getTypeClass();
+
+ Any aRet;
+
+ // convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to STRUCT, EXCEPTION ----------------------------------------------------------
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ {
+ // same types or destination type is derived source type?
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ if (!typelib_typedescription_isAssignableFrom( aDestTD.get(), aSourceTD.get() ))
+ {
+ throw CannotConvertException(
+ "value is not of same or derived type!",
+ Reference< XInterface >(), aDestinationClass,
+ FailReason::SOURCE_IS_NO_DERIVED_TYPE, 0 );
+ }
+ aRet.setValue( rVal.getValue(), aDestTD.get() ); // evtl. .uP.cAsT.
+ break;
+ }
+ // --- to INTERFACE -------------------------------------------------------------------------
+ case TypeClass_INTERFACE:
+ {
+ if (! rVal.hasValue())
+ {
+ // void -> interface (null)
+ void * null_ref = nullptr;
+ // coverity[var_deref_model : FALSE] - null_ref will not be derefed in this case
+ aRet.setValue( &null_ref, aDestType );
+ break;
+ }
+
+ auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
+ rVal);
+ if (!ifc || !ifc->is())
+ {
+ throw CannotConvertException(
+ "value is not interface",
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ aRet = (*ifc)->queryInterface(aDestType );
+ if (! aRet.hasValue())
+ {
+ throw CannotConvertException(
+ "value does not implement " + aDestType.getTypeName(),
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ break;
+ }
+ // --- to SEQUENCE --------------------------------------------------------------------------
+ case TypeClass_SEQUENCE:
+ {
+ if (aSourceClass==TypeClass_SEQUENCE)
+ {
+ if( aSourceType == aDestType )
+ return rVal;
+
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ // For a sequence type notation "[]...", SequenceTypeDescription in
+ // cppuhelper/source/typemanager.cxx resolves the "..." component type notation part
+ // only lazily, so it could happen here that bad user input (e.g., "[]" or "[]foo" from
+ // a Basic script CreateUnoValue call) leads to a bad but as-of-yet undetected
+ // aDestType, so check it here; this is less likely an issue for the non-sequence type
+ // classes, whose notation is not resolved lazily based on their syntax:
+ if (!aDestTD.is()) {
+ throw css::lang::IllegalArgumentException(
+ "Bad XTypeConverter::convertTo destination " + aDestType.getTypeName(),
+ static_cast<cppu::OWeakObject *>(this), 1);
+ }
+ typelib_TypeDescription * pSourceElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pSourceElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aSourceTD.get())->pType );
+ typelib_TypeDescription * pDestElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pDestElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aDestTD.get())->pType );
+
+ sal_uInt32 nPos = (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->nElements;
+ uno_Sequence * pRet = nullptr;
+ uno_sequence_construct(
+ &pRet, aDestTD.get(), nullptr, nPos,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ aRet.setValue( &pRet, aDestTD.get() );
+ uno_destructData(
+ &pRet, aDestTD.get(),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ // decr ref count
+
+ char * pDestElements = (*static_cast<uno_Sequence * const *>(aRet.getValue()))->elements;
+ const char * pSourceElements =
+ (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->elements;
+
+ while (nPos--)
+ {
+ char * pDestPos = pDestElements + (nPos * pDestElementTD->nSize);
+ const char * pSourcePos = pSourceElements + (nPos * pSourceElementTD->nSize);
+
+ Any aElement(
+ convertTo( Any( pSourcePos, pSourceElementTD ), pDestElementTD->pWeakRef ) );
+
+ if (!uno_assignData(
+ pDestPos, pDestElementTD,
+ (pDestElementTD->eTypeClass == typelib_TypeClass_ANY
+ ? &aElement
+ : const_cast< void * >( aElement.getValue() )),
+ pDestElementTD,
+ reinterpret_cast< uno_QueryInterfaceFunc >(
+ cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) ))
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pDestElementTD );
+ TYPELIB_DANGER_RELEASE( pSourceElementTD );
+ }
+ break;
+ }
+ // --- to ENUM ------------------------------------------------------------------------------
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aDestType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos = -1;
+
+ if (aSourceClass==TypeClass_STRING)
+ {
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (o3tl::forceAccess<OUString>(rVal)->equalsIgnoreAsciiCase(
+ OUString::unacquired(&reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]) ))
+ break;
+ }
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude some unwanted types for toHyper()
+ aSourceClass!=TypeClass_BOOLEAN &&
+ aSourceClass!=TypeClass_CHAR)
+ {
+ sal_Int32 nEnumValue = static_cast<sal_Int32>(toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ));
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ }
+
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value cannot be converted to demanded ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet.setValue(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos],
+ aEnumTD.get() );
+
+ break;
+ }
+
+ default:
+ // else simple type conversion possible?
+ try
+ {
+ aRet = convertToSimpleType( rVal, aDestinationClass );
+ }
+ catch (IllegalArgumentException &)
+ {
+ // ...FailReason::INVALID is thrown
+ }
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+
+Any TypeConverter_Impl::convertToSimpleType( const Any& rVal, TypeClass aDestinationClass )
+{
+ switch (aDestinationClass)
+ {
+ // only simple Conversion of _simple_ types
+ case TypeClass_VOID:
+ case TypeClass_BOOLEAN:
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ case TypeClass_CHAR:
+ case TypeClass_STRING:
+ case TypeClass_ANY:
+ break;
+
+ default:
+ throw IllegalArgumentException(
+ "destination type is not simple!",
+ Reference< XInterface >(), sal_Int16(1) );
+ }
+
+ const Type& aSourceType = rVal.getValueType();
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ if (aDestinationClass == aSourceClass)
+ return rVal;
+
+ Any aRet;
+
+ // Convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to BOOL ------------------------------------------------------------------------------
+ case TypeClass_BOOLEAN:
+ switch (aSourceClass)
+ {
+ default:
+ aRet <<= (toDouble( rVal ) != 0.0);
+ break;
+ case TypeClass_ENUM: // exclude enums
+ break;
+
+ case TypeClass_STRING:
+ {
+ const OUString & aStr = *o3tl::forceAccess<OUString>(rVal);
+ if ( aStr == "0" || aStr.equalsIgnoreAsciiCase( "false" ))
+ {
+ aRet <<= false;
+ }
+ else if ( aStr == "1" || aStr.equalsIgnoreAsciiCase( "true" ))
+ {
+ aRet <<= true;
+ }
+ else
+ {
+ throw CannotConvertException(
+ "STRING has no boolean value, " + aStr,
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_BOOL, 0 );
+ }
+ }
+ }
+ break;
+
+ // --- to CHAR, BYTE ------------------------------------------------------------------------
+ case TypeClass_CHAR:
+ {
+ if (aSourceClass==TypeClass_STRING)
+ {
+ auto const s = o3tl::forceAccess<OUString>(rVal);
+ if (s->getLength() == 1) // single char
+ aRet <<= (*s)[0];
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude enums, chars
+ aSourceClass!=TypeClass_CHAR)
+ {
+ aRet <<= sal_Unicode(toHyper( rVal, 0, 0xffff )); // range
+ }
+ break;
+ }
+ case TypeClass_BYTE:
+ aRet <<= static_cast<sal_Int8>( toHyper( rVal, -sal_Int64(0x80), 0x7f ) );
+ break;
+
+ // --- to SHORT, UNSIGNED SHORT -------------------------------------------------------------
+ case TypeClass_SHORT:
+ aRet <<= static_cast<sal_Int16>( toHyper( rVal, -sal_Int64(0x8000), 0x7fff ) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= static_cast<sal_uInt16>( toHyper( rVal, 0, 0xffff ) );
+ break;
+
+ // --- to LONG, UNSIGNED LONG ---------------------------------------------------------------
+ case TypeClass_LONG:
+ aRet <<= static_cast<sal_Int32>( toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= static_cast<sal_uInt32>( toHyper( rVal, 0, 0xffffffff ) );
+ break;
+
+ // --- to HYPER, UNSIGNED HYPER--------------------------------------------
+ case TypeClass_HYPER:
+ aRet <<= toHyper( rVal, SAL_MIN_INT64, SAL_MAX_INT64 );
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ aRet <<= static_cast<sal_uInt64>( toHyper( rVal, 0 ) );
+ break;
+
+ // --- to FLOAT, DOUBLE ---------------------------------------------------------------------
+ case TypeClass_FLOAT:
+ aRet <<= static_cast<float>( toDouble( rVal, -FLT_MAX, FLT_MAX ) );
+ break;
+ case TypeClass_DOUBLE:
+ aRet <<= toDouble( rVal, -DBL_MAX, DBL_MAX );
+ break;
+
+ // --- to STRING ----------------------------------------------------------------------------
+ case TypeClass_STRING:
+ switch (aSourceClass)
+ {
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aSourceType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos;
+ sal_Int32 nEnumValue = *static_cast<sal_Int32 const *>(rVal.getValue());
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value is not ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet <<= OUString::unacquired(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]);
+
+ break;
+ }
+
+ case TypeClass_BOOLEAN:
+ aRet <<= *o3tl::forceAccess<bool>(rVal) ?
+ OUString("true") :
+ OUString("false");
+ break;
+ case TypeClass_CHAR:
+ aRet <<= OUString(*o3tl::forceAccess<sal_Unicode>(rVal));
+ break;
+
+ case TypeClass_BYTE:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int8>(rVal) );
+ break;
+ case TypeClass_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int16>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt16>(rVal) );
+ break;
+ case TypeClass_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int32>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt32>(rVal) );
+ break;
+ case TypeClass_HYPER:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int64>(rVal) );
+ break;
+// case TypeClass_UNSIGNED_HYPER:
+// aRet <<= OUString::valueOf( (sal_Int64)*(sal_uInt64 const *)rVal.getValue() );
+// break;
+ // handle unsigned hyper like double
+
+ default:
+ aRet <<= OUString::number( toDouble( rVal ) );
+ }
+ break;
+
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_stoc_TypeConverter_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new stoc_tcv::TypeConverter_Impl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx
new file mode 100644
index 000000000..b9e2ca4e9
--- /dev/null
+++ b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx
@@ -0,0 +1,187 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <osl/thread.h>
+#include <rtl/string.h>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace {
+
+class Translator:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator>
+{
+public:
+ Translator() {}
+
+ Translator(const Translator&) = delete;
+ Translator& operator=(const Translator&) = delete;
+
+ 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;
+
+ virtual OUString SAL_CALL
+ translateToInternal(OUString const & externalUriReference) override;
+
+ virtual OUString SAL_CALL
+ translateToExternal(OUString const & internalUriReference) override;
+
+private:
+ virtual ~Translator() override {}
+};
+
+OUString Translator::getImplementationName()
+{
+ return "com.sun.star.comp.uri.ExternalUriReferenceTranslator";
+}
+
+sal_Bool Translator::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Translator::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.ExternalUriReferenceTranslator" };
+ return s;
+}
+
+OUString Translator::translateToInternal(
+ OUString const & externalUriReference)
+{
+ if (!externalUriReference.matchIgnoreAsciiCase("file:/"))
+ {
+ return externalUriReference;
+ }
+ sal_Int32 i = RTL_CONSTASCII_LENGTH("file:");
+ OUStringBuffer buf(128);
+ buf.append(externalUriReference.subView(0, i));
+ // Some environments (e.g., Java) produce illegal file URLs without an
+ // authority part; treat them as having an empty authority part:
+ if (!externalUriReference.match("//", i))
+ {
+ buf.append("//");
+ }
+ rtl_TextEncoding encoding = osl_getThreadTextEncoding();
+ for (bool path = true;;) {
+ sal_Int32 j = i;
+ while (j != externalUriReference.getLength()
+ && externalUriReference[j] != '#'
+ && (!path || externalUriReference[j] != '/'))
+ {
+ ++j;
+ }
+ if (j != i) {
+ OUString seg(
+ rtl::Uri::encode(
+ rtl::Uri::decode(
+ externalUriReference.copy(i, j - i),
+ rtl_UriDecodeStrict, encoding),
+ rtl_UriCharClassPchar, rtl_UriEncodeStrict,
+ RTL_TEXTENCODING_UTF8));
+ if (seg.isEmpty()) {
+ return OUString();
+ }
+ buf.append(seg);
+ }
+ if (j == externalUriReference.getLength()) {
+ break;
+ }
+ buf.append(externalUriReference[j]);
+ path = externalUriReference[j] == '/';
+ i = j + 1;
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString Translator::translateToExternal(
+ OUString const & internalUriReference)
+{
+ if (!internalUriReference.matchIgnoreAsciiCase("file://"))
+ {
+ return internalUriReference;
+ }
+ sal_Int32 i = RTL_CONSTASCII_LENGTH("file://");
+ OUStringBuffer buf(128);
+ buf.append(internalUriReference.subView(0, i));
+ rtl_TextEncoding encoding = osl_getThreadTextEncoding();
+ for (bool path = true;;) {
+ sal_Int32 j = i;
+ while (j != internalUriReference.getLength()
+ && internalUriReference[j] != '#'
+ && (!path || internalUriReference[j] != '/'))
+ {
+ ++j;
+ }
+ if (j != i) {
+ // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead
+ // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious
+ // non--UTF-8 octets like "%FE" are copied verbatim:
+ OUString seg(
+ rtl::Uri::encode(
+ rtl::Uri::decode(
+ internalUriReference.copy(i, j - i),
+ rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8),
+ rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes,
+ encoding));
+ if (seg.isEmpty()) {
+ return OUString();
+ }
+ buf.append(seg);
+ }
+ if (j == internalUriReference.getLength()) {
+ break;
+ }
+ buf.append(internalUriReference[j]);
+ path = internalUriReference[j] == '/';
+ i = j + 1;
+ }
+ return buf.makeStringAndClear();
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_ExternalUriReferenceTranslator_get_implementation(css::uno::XComponentContext* ,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Translator);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReference.cxx b/stoc/source/uriproc/UriReference.cxx
new file mode 100644
index 000000000..e8f7db0bf
--- /dev/null
+++ b/stoc/source/uriproc/UriReference.cxx
@@ -0,0 +1,183 @@
+/* -*- 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 <sal/config.h>
+
+#include <cassert>
+
+#include "UriReference.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+using stoc::uriproc::UriReference;
+
+UriReference::UriReference(
+ OUString const & scheme, bool bHasAuthority,
+ OUString const & authority, OUString const & path,
+ bool bHasQuery, OUString const & query):
+ m_path(path),
+ m_scheme(scheme),
+ m_authority(authority),
+ m_query(query),
+ m_hasAuthority(bHasAuthority),
+ m_hasQuery(bHasQuery),
+ m_hasFragment(false)
+{
+ assert(authority.isEmpty() || bHasAuthority);
+ assert(query.isEmpty() || bHasQuery);
+}
+
+UriReference::~UriReference() {}
+
+OUString UriReference::getUriReference()
+{
+ std::lock_guard g(m_mutex);
+ OUStringBuffer buf(128);
+ if (!m_scheme.isEmpty()) {
+ buf.append(m_scheme);
+ buf.append(':');
+ }
+ appendSchemeSpecificPart(buf);
+ if (m_hasFragment) {
+ buf.append('#');
+ buf.append(m_fragment);
+ }
+ return buf.makeStringAndClear();
+}
+
+bool UriReference::isAbsolute() const {
+ return !m_scheme.isEmpty();
+}
+
+
+OUString UriReference::getSchemeSpecificPart()
+{
+ std::lock_guard g(m_mutex);
+ OUStringBuffer buf;
+ appendSchemeSpecificPart(buf);
+ return buf.makeStringAndClear();
+}
+
+bool UriReference::isHierarchical() {
+ std::lock_guard g(m_mutex);
+ return m_scheme.isEmpty() || m_hasAuthority || m_path.startsWith("/");
+}
+
+bool UriReference::hasAuthority() const {
+ return m_hasAuthority;
+}
+
+const OUString& UriReference::getAuthority() const {
+ return m_authority;
+}
+
+OUString UriReference::getPath() {
+ std::lock_guard g(m_mutex);
+ return m_path;
+}
+
+bool UriReference::hasRelativePath() {
+ std::lock_guard g(m_mutex);
+ return !m_hasAuthority
+ && (m_path.isEmpty() || m_path[0] != '/');
+}
+
+sal_Int32 UriReference::getPathSegmentCount()
+{
+ std::lock_guard g(m_mutex);
+ if (m_path.isEmpty()) {
+ return 0;
+ } else {
+ sal_Int32 n = m_path[0] == '/' ? 0 : 1;
+ for (sal_Int32 i = 0;; ++i) {
+ i = m_path.indexOf('/', i);
+ if (i < 0) {
+ break;
+ }
+ ++n;
+ }
+ return n;
+ }
+}
+
+OUString UriReference::getPathSegment(sal_Int32 index)
+{
+ std::lock_guard g(m_mutex);
+ if (!m_path.isEmpty() && index >= 0) {
+ for (sal_Int32 i = m_path[0] == '/' ? 1 : 0;; ++i) {
+ if (index-- == 0) {
+ sal_Int32 j = m_path.indexOf('/', i);
+ return j < 0 ? m_path.copy(i) : m_path.copy(i, j - i);
+ }
+ i = m_path.indexOf('/', i);
+ if (i < 0) {
+ break;
+ }
+ }
+ }
+ return OUString();
+}
+
+bool UriReference::hasQuery() const {
+ return m_hasQuery;
+}
+
+const OUString& UriReference::getQuery() const {
+ return m_query;
+}
+
+bool UriReference::hasFragment() {
+ std::lock_guard g(m_mutex);
+ return m_hasFragment;
+}
+
+OUString UriReference::getFragment() {
+ std::lock_guard g(m_mutex);
+ return m_fragment;
+}
+
+void UriReference::setFragment(OUString const & fragment)
+{
+ std::lock_guard g(m_mutex);
+ m_hasFragment = true;
+ m_fragment = fragment;
+}
+
+void UriReference::clearFragment() {
+ std::lock_guard g(m_mutex);
+ m_hasFragment = false;
+ m_fragment.clear();
+}
+
+void UriReference::appendSchemeSpecificPart(OUStringBuffer & buffer) const
+{
+ if (m_hasAuthority) {
+ buffer.append("//");
+ buffer.append(m_authority);
+ }
+ buffer.append(m_path);
+ if (m_hasQuery) {
+ buffer.append('?');
+ buffer.append(m_query);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReference.hxx b/stoc/source/uriproc/UriReference.hxx
new file mode 100644
index 000000000..e16453720
--- /dev/null
+++ b/stoc/source/uriproc/UriReference.hxx
@@ -0,0 +1,112 @@
+/* -*- 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 .
+ */
+
+#ifndef INCLUDED_STOC_SOURCE_URIPROC_URIREFERENCE_HXX
+#define INCLUDED_STOC_SOURCE_URIPROC_URIREFERENCE_HXX
+
+#include <mutex>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <rtl/ustrbuf.hxx>
+
+namespace stoc::uriproc {
+
+class UriReference {
+public:
+ UriReference(
+ OUString const & scheme, bool hasAuthority,
+ OUString const & authority, OUString const & path,
+ bool hasQuery, OUString const & query);
+
+ ~UriReference();
+
+ /// @throws css::uno::RuntimeException
+ OUString getUriReference();
+
+ /// @throws css::uno::RuntimeException
+ bool isAbsolute() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getScheme() const { return m_scheme;}
+
+ /// @throws css::uno::RuntimeException
+ OUString getSchemeSpecificPart();
+
+ /// @throws css::uno::RuntimeException
+ bool isHierarchical();
+
+ /// @throws css::uno::RuntimeException
+ bool hasAuthority() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getAuthority() const;
+
+ /// @throws css::uno::RuntimeException
+ OUString getPath();
+
+ /// @throws css::uno::RuntimeException
+ bool hasRelativePath();
+
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getPathSegmentCount();
+
+ /// @throws css::uno::RuntimeException
+ OUString getPathSegment(sal_Int32 index);
+
+ /// @throws css::uno::RuntimeException
+ bool hasQuery() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getQuery() const;
+
+ /// @throws css::uno::RuntimeException
+ bool hasFragment();
+
+ /// @throws css::uno::RuntimeException
+ OUString getFragment();
+
+ /// @throws css::uno::RuntimeException
+ void setFragment(OUString const & fragment);
+
+ /// @throws css::uno::RuntimeException
+ void clearFragment();
+
+ std::mutex m_mutex;
+ OUString m_path;
+
+private:
+ UriReference(UriReference const &) = delete;
+ void operator =(UriReference const &) = delete;
+
+ void appendSchemeSpecificPart(OUStringBuffer & buffer) const;
+
+ OUString m_scheme;
+ OUString m_authority;
+ OUString m_query;
+ OUString m_fragment;
+ bool m_hasAuthority;
+ bool m_hasQuery;
+ bool m_hasFragment;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReferenceFactory.cxx b/stoc/source/uriproc/UriReferenceFactory.cxx
new file mode 100644
index 000000000..254097c17
--- /dev/null
+++ b/stoc/source/uriproc/UriReferenceFactory.cxx
@@ -0,0 +1,719 @@
+/* -*- 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 <sal/config.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uri/RelativeUriExcessParentSegments.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/uri/XUriSchemeParser.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/character.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include "UriReference.hxx"
+
+namespace {
+
+bool equalIgnoreEscapeCase(std::u16string_view s1, std::u16string_view s2) {
+ if (s1.size() == s2.size()) {
+ for (size_t i = 0; i < s1.size();) {
+ if (s1[i] == '%' && s2[i] == '%' && s1.size() - i > 2
+ && rtl::isAsciiHexDigit(s1[i + 1])
+ && rtl::isAsciiHexDigit(s1[i + 2])
+ && rtl::isAsciiHexDigit(s2[i + 1])
+ && rtl::isAsciiHexDigit(s2[i + 2])
+ && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
+ && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
+ {
+ i += 3;
+ } else if (s1[i] != s2[i]) {
+ return false;
+ } else {
+ ++i;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+sal_Int32 parseScheme(std::u16string_view uriReference) {
+ if (uriReference.size() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
+ for (size_t i = 0; i < uriReference.size(); ++i) {
+ sal_Unicode c = uriReference[i];
+ if (c == ':') {
+ return i;
+ } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
+ && c != '+' && c != '-' && c != '.')
+ {
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+class UriReference:
+ public cppu::WeakImplHelper<css::uri::XUriReference>
+{
+public:
+ UriReference(
+ OUString const & scheme, bool bHasAuthority,
+ OUString const & authority, OUString const & path,
+ bool bHasQuery, OUString const & query):
+ m_base(
+ scheme, bHasAuthority, authority, path, bHasQuery,
+ query)
+ {}
+
+ UriReference(const UriReference&) = delete;
+ UriReference& operator=(const UriReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return m_base.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return m_base.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return m_base.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return m_base.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return m_base.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return m_base.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return m_base.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return m_base.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return m_base.hasRelativePath(); }
+
+ virtual sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return m_base.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return m_base.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return m_base.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return m_base.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return m_base.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return m_base.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { m_base.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { m_base.clearFragment(); }
+
+private:
+ virtual ~UriReference() override {}
+
+ stoc::uriproc::UriReference m_base;
+};
+
+css::uno::Reference< css::uri::XUriReference > parseGeneric(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ sal_Int32 len = schemeSpecificPart.getLength();
+ sal_Int32 i = 0;
+ bool hasAuthority = false;
+ OUString authority;
+ if (len - i >= 2 && schemeSpecificPart[i] == '/'
+ && schemeSpecificPart[i + 1] == '/')
+ {
+ i += 2;
+ sal_Int32 n = i;
+ while (i < len && schemeSpecificPart[i] != '/'
+ && schemeSpecificPart[i] != '?') {
+ ++i;
+ }
+ hasAuthority = true;
+ authority = schemeSpecificPart.copy(n, i - n);
+ }
+ sal_Int32 n = i;
+ i = schemeSpecificPart.indexOf('?', i);
+ if (i == -1) {
+ i = len;
+ }
+ OUString path = schemeSpecificPart.copy(n, i - n);
+ bool hasQuery = false;
+ OUString query;
+ if (i != len) {
+ hasQuery = true;
+ query = schemeSpecificPart.copy(i + 1);
+ }
+ return new UriReference(
+ scheme, hasAuthority, authority, path, hasQuery, query);
+}
+
+struct Segment {
+ bool leadingSlash;
+ bool excessParent;
+ std::u16string_view segment;
+
+ Segment(bool theLeadingSlash, bool theExcessParent, std::u16string_view theSegment):
+ leadingSlash(theLeadingSlash), excessParent(theExcessParent), segment(theSegment) {}
+};
+
+std::pair<std::vector<Segment>, bool> processSegments(
+ std::u16string_view first, std::u16string_view second, bool processSpecialSegments)
+{
+ std::vector<Segment> segments;
+ bool processed = false;
+ std::u16string_view const * half = &first;
+ // later checks for `half == &first` and `half == &second` rely on the fact that `first` and
+ // `second` are passed by value, in case a caller passes the same object for both arguments
+ std::size_t index = 0;
+ bool slash = false;
+ if (index == half->length()) {
+ half = &second;
+ index = 0;
+ }
+ if (index != half->length()) {
+ if ((*half)[index] == u'/') {
+ slash = true;
+ ++index;
+ }
+ for (;;) {
+ if (index == half->length() && half == &first) {
+ half = &second;
+ index = 0;
+ }
+ if (index == half->length()) {
+ if (slash) {
+ segments.emplace_back(true, false, std::u16string_view());
+ }
+ break;
+ }
+ auto const n = std::min(half->find(u'/', index), half->length());
+ auto const leadingSlash = slash;
+ auto const segment = half->substr(index, n - index);
+ auto const process = processSpecialSegments || half == &second;
+ index = n;
+ slash = false;
+ if (index == half->length() && half == &first) {
+ half = &second;
+ index = 0;
+ }
+ if (index != half->length() && (*half)[index] == u'/') {
+ slash = true;
+ ++index;
+ }
+ if (process) {
+ if (segment == u".") {
+ slash = leadingSlash;
+ processed = true;
+ continue;
+ } else if (segment == u"..") {
+ if (segments.empty() || segments.back().excessParent) {
+ segments.emplace_back(leadingSlash, true, segment);
+ } else {
+ if (leadingSlash) {
+ segments.pop_back();
+ }
+ slash = leadingSlash;
+ }
+ processed = true;
+ continue;
+ }
+ }
+ segments.emplace_back(leadingSlash, false, segment);
+ }
+ }
+ return {segments, processed};
+}
+
+class Factory:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriReferenceFactory>
+{
+public:
+ explicit Factory(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ m_context(context) {}
+
+ Factory(const Factory&) = delete;
+ Factory& operator=(const Factory&) = delete;
+
+ 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;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ parse(OUString const & uriReference) override;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ makeAbsolute(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool processAdditionalSpecialSegments,
+ css::uri::RelativeUriExcessParentSegments excessParentSegments) override;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ makeRelative(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool preferAuthorityOverRelativePath,
+ sal_Bool preferAbsoluteOverRelativePath,
+ sal_Bool encodeRetainedSpecialSegments) override;
+
+private:
+ virtual ~Factory() override {}
+
+ css::uno::Reference< css::uri::XUriReference > clone(
+ css::uno::Reference< css::uri::XUriReference > const & uriReference)
+ { return parse(uriReference->getUriReference()); }
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+OUString Factory::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriReferenceFactory";
+}
+
+sal_Bool Factory::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.UriReferenceFactory" };
+ return s;
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::parse(
+ OUString const & uriReference)
+{
+ sal_Int32 fragment = uriReference.indexOf('#');
+ if (fragment == -1) {
+ fragment = uriReference.getLength();
+ }
+ OUString scheme;
+ OUString schemeSpecificPart;
+ OUString serviceName;
+ sal_Int32 n = parseScheme(uriReference);
+ assert(n < fragment);
+ if (n >= 0) {
+ scheme = uriReference.copy(0, n);
+ schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
+ OUStringBuffer buf(128);
+ buf.append("com.sun.star.uri.UriSchemeParser_");
+ for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
+ sal_Unicode c = scheme[i];
+ if (rtl::isAsciiUpperCase(c)) {
+ buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
+ } else if (c == '+') {
+ buf.append("PLUS");
+ } else if (c == '-') {
+ buf.append("HYPHEN");
+ } else if (c == '.') {
+ buf.append("DOT");
+ } else {
+ assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
+ buf.append(c);
+ }
+ }
+ serviceName = buf.makeStringAndClear();
+ } else {
+ schemeSpecificPart = uriReference.copy(0, fragment);
+ }
+ css::uno::Reference< css::uri::XUriSchemeParser > parser;
+ if (!serviceName.isEmpty()) {
+ css::uno::Reference< css::lang::XMultiComponentFactory > factory(
+ m_context->getServiceManager());
+ if (factory.is()) {
+ css::uno::Reference< css::uno::XInterface > service;
+ try {
+ service = factory->createInstanceWithContext(
+ serviceName, m_context);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (const css::uno::Exception &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "creating service " + serviceName,
+ static_cast< cppu::OWeakObject * >(this),
+ anyEx);
+ }
+ if (service.is()) {
+ parser.set( service, css::uno::UNO_QUERY_THROW);
+ }
+ }
+ }
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ parser.is()
+ ? parser->parse(scheme, schemeSpecificPart)
+ : parseGeneric(scheme, schemeSpecificPart));
+ if (uriRef.is() && fragment != uriReference.getLength()) {
+ uriRef->setFragment(uriReference.copy(fragment + 1));
+ }
+ return uriRef;
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool processAdditionalSpecialSegments,
+ css::uri::RelativeUriExcessParentSegments excessParentSegments)
+{
+ if (!baseUriReference.is() || !baseUriReference->isAbsolute()
+ || !uriReference.is()) {
+ return nullptr;
+ } else if (uriReference->isAbsolute()) {
+ if (processAdditionalSpecialSegments) {
+ auto const path = uriReference->getPath();
+ auto [segments, proc] = processSegments(path, {}, true);
+ if (proc) {
+ OUStringBuffer abs(uriReference->getScheme());
+ abs.append(':');
+ if (uriReference->hasAuthority()) {
+ abs.append("//");
+ abs.append(uriReference->getAuthority());
+ }
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ if (uriReference->hasQuery()) {
+ abs.append('?');
+ abs.append(uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append('#');
+ abs.append(uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ }
+ }
+ return clone(uriReference);
+ } else if (!uriReference->hasAuthority()
+ && uriReference->getPath().isEmpty()) {
+ OUStringBuffer abs(baseUriReference->getScheme());
+ abs.append(':');
+ if (baseUriReference->hasAuthority()) {
+ abs.append("//");
+ abs.append(baseUriReference->getAuthority());
+ }
+ abs.append(baseUriReference->getPath());
+ if (uriReference->hasQuery()) {
+ abs.append('?');
+ abs.append(uriReference->getQuery());
+ } else if (baseUriReference->hasQuery()) {
+ abs.append('?');
+ abs.append(baseUriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append('#');
+ abs.append(uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ } else {
+ OUStringBuffer abs(128);
+ abs.append(baseUriReference->getScheme());
+ abs.append(':');
+ if (uriReference->hasAuthority()) {
+ abs.append("//");
+ abs.append(uriReference->getAuthority());
+ } else if (baseUriReference->hasAuthority()) {
+ abs.append("//");
+ abs.append(baseUriReference->getAuthority());
+ }
+ if (uriReference->hasRelativePath()) {
+ auto path1 = baseUriReference->getPath();
+ if (path1.isEmpty()) {
+ if (baseUriReference->hasAuthority()) {
+ path1 = "/";
+ }
+ } else {
+ path1 = path1.copy(0, path1.lastIndexOf('/') + 1);
+ }
+ auto const path2 = uriReference->getPath();
+ auto [segments, _] = processSegments(path1, path2, processAdditionalSpecialSegments);
+ (void)_;
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ } else {
+ bool processed = false;
+ if (processAdditionalSpecialSegments) {
+ auto const path = uriReference->getPath();
+ auto [segments, proc] = processSegments(path, {}, true);
+ if (proc) {
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ processed = true;
+ }
+ }
+ if (!processed) {
+ abs.append(uriReference->getPath());
+ }
+ }
+ if (uriReference->hasQuery()) {
+ abs.append('?');
+ abs.append(uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append('#');
+ abs.append(uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ }
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool preferAuthorityOverRelativePath,
+ sal_Bool preferAbsoluteOverRelativePath,
+ sal_Bool encodeRetainedSpecialSegments)
+{
+ if (!baseUriReference.is() || !baseUriReference->isAbsolute()
+ || !uriReference.is()) {
+ return nullptr;
+ } else if (!uriReference->isAbsolute() || uriReference->hasRelativePath()
+ || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
+ uriReference->getScheme())) {
+ return clone(uriReference);
+ } else {
+ OUStringBuffer rel(128);
+ bool omitQuery = false;
+ if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
+ || !equalIgnoreEscapeCase(
+ baseUriReference->getAuthority(),
+ uriReference->getAuthority()))
+ {
+ if (uriReference->hasAuthority()) {
+ rel.append("//");
+ rel.append(uriReference->getAuthority());
+ }
+ rel.append(uriReference->getPath());
+ } else if ((equalIgnoreEscapeCase(
+ baseUriReference->getPath(), uriReference->getPath())
+ || (baseUriReference->getPath() == "/"
+ && uriReference->getPath().isEmpty()))
+ && baseUriReference->hasQuery() == uriReference->hasQuery()
+ && equalIgnoreEscapeCase(
+ baseUriReference->getQuery(), uriReference->getQuery()))
+ {
+ omitQuery = true;
+ } else {
+ sal_Int32 count1 = std::max< sal_Int32 >(
+ baseUriReference->getPathSegmentCount(), 1);
+ sal_Int32 count2 = std::max< sal_Int32 >(
+ uriReference->getPathSegmentCount(), 1);
+ sal_Int32 i = 0;
+ for (; i < std::min(count1, count2) - 1; ++i) {
+ if (!equalIgnoreEscapeCase(
+ baseUriReference->getPathSegment(i),
+ uriReference->getPathSegment(i)))
+ {
+ break;
+ }
+ }
+ if (i == 0
+ && (preferAbsoluteOverRelativePath || uriReference->hasQuery())
+ && (preferAuthorityOverRelativePath
+ || !uriReference->getPath().startsWith("//")))
+ {
+ if (uriReference->getPath().isEmpty()) {
+ if (!baseUriReference->getPath().isEmpty()
+ && baseUriReference->getPath() != "/")
+ {
+ rel.append('/');
+ }
+ } else if (uriReference->getPath() == "/") {
+ if (baseUriReference->getPath().isEmpty()
+ || baseUriReference->getPath() != "/")
+ {
+ rel.append('/');
+ }
+ } else {
+ if (uriReference->getPath().startsWith("//")) {
+ assert(uriReference->hasAuthority());
+ rel.append("//");
+ rel.append(uriReference->getAuthority());
+ }
+ rel.append(uriReference->getPath());
+ }
+ } else {
+ bool segments = false;
+ for (sal_Int32 j = i; j < count1 - 1; ++j) {
+ if (segments) {
+ rel.append('/');
+ }
+ rel.append("..");
+ segments = true;
+ }
+ if (i < count2 - 1
+ || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
+ {
+ if (!segments
+ && (uriReference->getPathSegment(i).isEmpty()
+ || (parseScheme(uriReference->getPathSegment(i))
+ >= 0)))
+ {
+ rel.append('.');
+ segments = true;
+ }
+ for (; i < count2; ++i) {
+ if (segments) {
+ rel.append('/');
+ }
+ OUString s(uriReference->getPathSegment(i));
+ if (encodeRetainedSpecialSegments && s == ".") {
+ rel.append("%2E");
+ } else if (encodeRetainedSpecialSegments && s == "..") {
+ rel.append("%2E%2E");
+ } else {
+ rel.append(s);
+ }
+ segments = true;
+ }
+ }
+ }
+ }
+ if (!omitQuery && uriReference->hasQuery()) {
+ rel.append('?');
+ rel.append(uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ rel.append('#');
+ rel.append(uriReference->getFragment());
+ }
+ return parse(rel.makeStringAndClear());
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Factory(rxContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx
new file mode 100644
index 000000000..dde6fcb06
--- /dev/null
+++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx
@@ -0,0 +1,198 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/XUriSchemeParser.hpp>
+#include <com/sun/star/uri/XVndSunStarExpandUrlReference.hpp>
+#include <com/sun/star/util/XMacroExpander.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include "UriReference.hxx"
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uri { class XUriReference; }
+
+namespace {
+
+bool parseSchemeSpecificPart(OUString const & part) {
+ // Liberally accepts both an empty opaque_part and an opaque_part that
+ // starts with a non-escaped "/":
+ return part.isEmpty()
+ || (!::rtl::Uri::decode(part, ::rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8).isEmpty());
+}
+
+class UrlReference:
+ public ::cppu::WeakImplHelper<css::uri::XVndSunStarExpandUrlReference>
+{
+public:
+ UrlReference(OUString const & scheme, OUString const & path):
+ base_(
+ scheme, false, OUString(), path, false,
+ OUString())
+ {}
+
+ UrlReference(const UrlReference&) = delete;
+ UrlReference& operator=(const UrlReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return base_.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return base_.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return base_.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return base_.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return base_.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return base_.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return base_.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return base_.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return base_.hasRelativePath(); }
+
+ virtual ::sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return base_.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return base_.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return base_.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return base_.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return base_.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return base_.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { base_.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { base_.clearFragment(); }
+
+ virtual OUString SAL_CALL expand(
+ css::uno::Reference< css::util::XMacroExpander > const & expander) override;
+
+private:
+ virtual ~UrlReference() override {}
+
+ stoc::uriproc::UriReference base_;
+};
+
+OUString UrlReference::expand(
+ css::uno::Reference< css::util::XMacroExpander > const & expander)
+{
+ if (!expander.is()) {
+ throw css::uno::RuntimeException("null expander passed to XVndSunStarExpandUrl.expand");
+ }
+ return expander->expandMacros(
+ ::rtl::Uri::decode(
+ getPath(), ::rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8));
+}
+
+class Parser:
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriSchemeParser>
+{
+public:
+ Parser() {}
+
+ Parser(const Parser&) = delete;
+ Parser& operator=(const Parser&) = delete;
+
+ 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;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ parse(
+ OUString const & scheme,
+ OUString const & schemeSpecificPart) override;
+
+private:
+ virtual ~Parser() override {}
+};
+
+OUString Parser::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand";
+}
+
+sal_Bool Parser::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
+{
+ return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand" };
+}
+
+css::uno::Reference< css::uri::XUriReference > Parser::parse(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ if (!parseSchemeSpecificPart(schemeSpecificPart)) {
+ return css::uno::Reference< css::uri::XUriReference >();
+ }
+ return new UrlReference(scheme, schemeSpecificPart);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTexpand_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ //TODO: single instance
+ return ::cppu::acquire(new Parser());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
new file mode 100644
index 000000000..a8203a811
--- /dev/null
+++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
@@ -0,0 +1,386 @@
+/* -*- 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 "UriReference.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/XUriSchemeParser.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/character.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <o3tl/safeint.hxx>
+
+#include <string_view>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uri { class XUriReference; }
+
+namespace {
+
+int getHexWeight(sal_Unicode c) {
+ return c >= '0' && c <= '9' ? static_cast< int >(c - '0')
+ : c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10)
+ : c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10)
+ : -1;
+}
+
+int parseEscaped(std::u16string_view part, sal_Int32 * index) {
+ if (part.size() - *index < 3 || part[*index] != '%') {
+ return -1;
+ }
+ int n1 = getHexWeight(part[*index + 1]);
+ int n2 = getHexWeight(part[*index + 2]);
+ if (n1 < 0 || n2 < 0) {
+ return -1;
+ }
+ *index += 3;
+ return (n1 << 4) | n2;
+}
+
+OUString parsePart(
+ std::u16string_view part, bool namePart, sal_Int32 * index)
+{
+ OUStringBuffer buf(64);
+ while (o3tl::make_unsigned(*index) < part.size()) {
+ sal_Unicode c = part[*index];
+ if (namePart ? c == '?' : c == '&' || c == '=') {
+ break;
+ } else if (c == '%') {
+ sal_Int32 i = *index;
+ int n = parseEscaped(part, &i);
+ if (n >= 0 && n <= 0x7F) {
+ buf.append(static_cast< sal_Unicode >(n));
+ } else if (n >= 0xC0 && n <= 0xFC) {
+ sal_Int32 encoded;
+ int shift;
+ sal_Int32 min;
+ if (n <= 0xDF) {
+ encoded = (n & 0x1F) << 6;
+ shift = 0;
+ min = 0x80;
+ } else if (n <= 0xEF) {
+ encoded = (n & 0x0F) << 12;
+ shift = 6;
+ min = 0x800;
+ } else if (n <= 0xF7) {
+ encoded = (n & 0x07) << 18;
+ shift = 12;
+ min = 0x10000;
+ } else if (n <= 0xFB) {
+ encoded = (n & 0x03) << 24;
+ shift = 18;
+ min = 0x200000;
+ } else {
+ encoded = 0;
+ shift = 24;
+ min = 0x4000000;
+ }
+ bool utf8 = true;
+ for (; shift >= 0; shift -= 6) {
+ n = parseEscaped(part, &i);
+ if (n < 0x80 || n > 0xBF) {
+ utf8 = false;
+ break;
+ }
+ encoded |= (n & 0x3F) << shift;
+ }
+ if (!utf8 || !rtl::isUnicodeScalarValue(encoded)
+ || encoded < min)
+ {
+ break;
+ }
+ buf.appendUtf32(encoded);
+ } else {
+ break;
+ }
+ *index = i;
+ } else {
+ buf.append(c);
+ ++*index;
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString encodeNameOrParamFragment(OUString const & fragment) {
+ static constexpr auto nameOrParamFragment = rtl::createUriCharClass(
+ u8"!$'()*+,-.0123456789:;@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~");
+ return rtl::Uri::encode(
+ fragment, nameOrParamFragment.data(), rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8);
+}
+
+bool parseSchemeSpecificPart(std::u16string_view part) {
+ size_t len = part.size();
+ sal_Int32 i = 0;
+ if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
+ return false;
+ }
+ if (o3tl::make_unsigned(i) == len) {
+ return true;
+ }
+ for (;;) {
+ ++i; // skip '?' or '&'
+ if (parsePart(part, false, &i).isEmpty() || o3tl::make_unsigned(i) == len
+ || part[i] != '=')
+ {
+ return false;
+ }
+ ++i;
+ parsePart(part, false, &i);
+ if (o3tl::make_unsigned(i) == len) {
+ return true;
+ }
+ if (part[i] != '&') {
+ return false;
+ }
+ }
+}
+
+class UrlReference:
+ public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference>
+{
+public:
+ UrlReference(OUString const & scheme, OUString const & path):
+ m_base(
+ scheme, false, OUString(), path, false, OUString())
+ {}
+
+ UrlReference(const UrlReference&) = delete;
+ UrlReference& operator=(const UrlReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return m_base.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return m_base.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return m_base.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return m_base.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return m_base.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return m_base.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return m_base.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return m_base.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return m_base.hasRelativePath(); }
+
+ virtual sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return m_base.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return m_base.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return m_base.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return m_base.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return m_base.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return m_base.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { m_base.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { m_base.clearFragment(); }
+
+ virtual OUString SAL_CALL getName() override;
+
+ virtual void SAL_CALL setName(OUString const & name) override;
+
+ virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override;
+
+ virtual OUString SAL_CALL getParameter(OUString const & key) override;
+
+ virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override;
+
+private:
+ virtual ~UrlReference() override {}
+
+ sal_Int32 findParameter(std::u16string_view key) const;
+
+ stoc::uriproc::UriReference m_base;
+};
+
+OUString UrlReference::getName() {
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = 0;
+ return parsePart(m_base.m_path, true, &i);
+}
+
+void SAL_CALL UrlReference::setName(OUString const & name)
+{
+ if (name.isEmpty())
+ throw css::lang::IllegalArgumentException(
+ OUString(), *this, 1);
+
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = 0;
+ parsePart(m_base.m_path, true, &i);
+
+ m_base.m_path = encodeNameOrParamFragment(name) + m_base.m_path.subView(i);
+}
+
+sal_Bool UrlReference::hasParameter(OUString const & key)
+{
+ std::lock_guard g(m_base.m_mutex);
+ return findParameter(key) >= 0;
+}
+
+OUString UrlReference::getParameter(OUString const & key)
+{
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = findParameter(key);
+ return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
+}
+
+void UrlReference::setParameter(OUString const & key, OUString const & value)
+{
+ if (key.isEmpty())
+ throw css::lang::IllegalArgumentException(
+ OUString(), *this, 1);
+
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = findParameter(key);
+ bool bExistent = ( i>=0 );
+ if (!bExistent) {
+ i = m_base.m_path.getLength();
+ }
+
+ OUStringBuffer newPath(128);
+ newPath.append(m_base.m_path.subView(0, i));
+ if (!bExistent) {
+ newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
+ newPath.append(encodeNameOrParamFragment(key));
+ newPath.append('=');
+ }
+ newPath.append(encodeNameOrParamFragment(value));
+ if (bExistent) {
+ /*oldValue = */
+ parsePart(m_base.m_path, false, &i); // skip key
+ newPath.append(m_base.m_path.subView(i));
+ }
+
+ m_base.m_path = newPath.makeStringAndClear();
+}
+
+sal_Int32 UrlReference::findParameter(std::u16string_view key) const {
+ sal_Int32 i = 0;
+ parsePart(m_base.m_path, true, &i); // skip name
+ for (;;) {
+ if (i == m_base.m_path.getLength()) {
+ return -1;
+ }
+ ++i; // skip '?' or '&'
+ OUString k = parsePart(m_base.m_path, false, &i);
+ ++i; // skip '='
+ if (k == key) {
+ return i;
+ }
+ parsePart(m_base.m_path, false, &i); // skip value
+ }
+}
+
+class Parser:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriSchemeParser>
+{
+public:
+ Parser() {}
+
+ Parser(const Parser&) = delete;
+ Parser& operator=(const Parser&) = delete;
+
+ 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;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ parse(
+ OUString const & scheme, OUString const & schemeSpecificPart) override;
+
+private:
+ virtual ~Parser() override {}
+};
+
+OUString Parser::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript";
+}
+
+sal_Bool Parser::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
+{
+ return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
+}
+
+css::uno::Reference< css::uri::XUriReference >
+Parser::parse(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ if (!parseSchemeSpecificPart(schemeSpecificPart)) {
+ return nullptr;
+ }
+ return new UrlReference(scheme, schemeSpecificPart);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ //TODO: single instance
+ return ::cppu::acquire(new Parser());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx
new file mode 100644
index 000000000..2a3211a08
--- /dev/null
+++ b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+
+namespace {
+
+class Factory:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XVndSunStarPkgUrlReferenceFactory>
+{
+public:
+ explicit Factory(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ m_context(context) {}
+
+ Factory(const Factory&) = delete;
+ Factory& operator=(const Factory&) = delete;
+
+ 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;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ createVndSunStarPkgUrlReference(
+ css::uno::Reference< css::uri::XUriReference > const & authority) override;
+
+private:
+ virtual ~Factory() override {}
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+OUString Factory::getImplementationName()
+{
+ return "com.sun.star.comp.uri.VndSunStarPkgUrlReferenceFactory";
+}
+
+sal_Bool Factory::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory" };
+ return s;
+}
+
+css::uno::Reference< css::uri::XUriReference >
+Factory::createVndSunStarPkgUrlReference(
+ css::uno::Reference< css::uri::XUriReference > const & authority)
+{
+ if (!authority.is()) {
+ throw css::uno::RuntimeException(
+ "null authority passed to"
+ " XVndSunStarPkgUrlReferenceFactory.createVndSunStarPkgUrlReference");
+ }
+ if (authority->isAbsolute() && !authority->hasFragment()) {
+ OUString buf =
+ "vnd.sun.star.pkg://" +
+ rtl::Uri::encode(
+ authority->getUriReference(), rtl_UriCharClassRegName,
+ rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8);
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ css::uri::UriReferenceFactory::create(m_context)->parse(
+ buf));
+ return uriRef;
+ } else {
+ return css::uno::Reference< css::uri::XUriReference >();
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_VndSunStarPkgUrlReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Factory(rxContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */