summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/shared
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/cpp_uno/shared')
-rw-r--r--bridges/source/cpp_uno/shared/bridge.cxx210
-rw-r--r--bridges/source/cpp_uno/shared/component.cxx224
-rw-r--r--bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx144
-rw-r--r--bridges/source/cpp_uno/shared/types.cxx117
-rw-r--r--bridges/source/cpp_uno/shared/unointerfaceproxy.cxx126
-rw-r--r--bridges/source/cpp_uno/shared/vtablefactory.cxx403
-rw-r--r--bridges/source/cpp_uno/shared/vtables.cxx146
7 files changed, 1370 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/shared/bridge.cxx b/bridges/source/cpp_uno/shared/bridge.cxx
new file mode 100644
index 000000000..3753341cc
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/bridge.cxx
@@ -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 .
+ */
+
+
+#include <bridge.hxx>
+
+#include <cppinterfaceproxy.hxx>
+#include <unointerfaceproxy.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <rtl/ustring.h>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+#include <uno/environment.h>
+#include <uno/mapping.h>
+
+namespace bridges::cpp_uno::shared {
+
+void freeMapping(uno_Mapping * pMapping)
+{
+ delete static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+}
+
+void acquireMapping(uno_Mapping * pMapping)
+{
+ static_cast< Bridge::Mapping * >( pMapping )->pBridge->acquire();
+}
+
+void releaseMapping(uno_Mapping * pMapping)
+{
+ static_cast< Bridge::Mapping * >( pMapping )->pBridge->release();
+}
+
+void cpp2unoMapping(
+ uno_Mapping * pMapping, void ** ppUnoI, void * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ assert(ppUnoI && pTypeDescr);
+ if (*ppUnoI)
+ {
+ (*static_cast< uno_Interface * >( *ppUnoI )->release)(
+ static_cast< uno_Interface * >( *ppUnoI ) );
+ *ppUnoI = nullptr;
+ }
+ if (!pCppI)
+ return;
+
+ Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+
+ // get object id of interface to be wrapped
+ rtl_uString * pOId = nullptr;
+ (*pBridge->pCppEnv->getObjectIdentifier)(
+ pBridge->pCppEnv, &pOId, pCppI );
+ assert(pOId);
+
+ // try to get any known interface from target environment
+ (*pBridge->pUnoEnv->getRegisteredInterface)(
+ pBridge->pUnoEnv, ppUnoI, pOId, pTypeDescr );
+
+ if (! *ppUnoI) // no existing interface, register new proxy interface
+ {
+ // try to publish a new proxy (refcount initially 1)
+ uno_Interface * pSurrogate
+ = bridges::cpp_uno::shared::UnoInterfaceProxy::create(
+ pBridge,
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI ),
+ pTypeDescr, pOId );
+
+ // proxy may be exchanged during registration
+ (*pBridge->pUnoEnv->registerProxyInterface)(
+ pBridge->pUnoEnv, reinterpret_cast< void ** >( &pSurrogate ),
+ freeUnoInterfaceProxy, pOId,
+ pTypeDescr );
+
+ *ppUnoI = pSurrogate;
+ }
+ ::rtl_uString_release( pOId );
+}
+
+void uno2cppMapping(
+ uno_Mapping * pMapping, void ** ppCppI, void * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ assert(ppCppI && pTypeDescr);
+ if (*ppCppI)
+ {
+ static_cast< ::com::sun::star::uno::XInterface * >( *ppCppI )->
+ release();
+ *ppCppI = nullptr;
+ }
+ if (!pUnoI)
+ return;
+
+ Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge;
+
+ // get object id of uno interface to be wrapped
+ rtl_uString * pOId = nullptr;
+ (*pBridge->pUnoEnv->getObjectIdentifier)(
+ pBridge->pUnoEnv, &pOId, pUnoI );
+ assert(pOId);
+
+ // try to get any known interface from target environment
+ (*pBridge->pCppEnv->getRegisteredInterface)(
+ pBridge->pCppEnv, ppCppI, pOId, pTypeDescr );
+
+ if (! *ppCppI) // no existing interface, register new proxy interface
+ {
+ // try to publish a new proxy (ref count initially 1)
+ com::sun::star::uno::XInterface * pProxy
+ = bridges::cpp_uno::shared::CppInterfaceProxy::create(
+ pBridge, static_cast< uno_Interface * >( pUnoI ),
+ pTypeDescr, pOId );
+
+ // proxy may be exchanged during registration
+ (*pBridge->pCppEnv->registerProxyInterface)(
+ pBridge->pCppEnv, reinterpret_cast< void ** >( &pProxy ),
+ freeCppInterfaceProxy, pOId,
+ pTypeDescr );
+
+ *ppCppI = pProxy;
+ }
+ ::rtl_uString_release( pOId );
+}
+
+uno_Mapping * Bridge::createMapping(
+ uno_ExtEnvironment * pCppEnv, uno_ExtEnvironment * pUnoEnv,
+ bool bExportCpp2Uno)
+{
+ Bridge * bridge = new Bridge(pCppEnv, pUnoEnv, bExportCpp2Uno);
+ // coverity[leaked_storage] - on purpose
+ return bExportCpp2Uno ? &bridge->aCpp2Uno : &bridge->aUno2Cpp;
+}
+
+void Bridge::acquire()
+{
+ if (++nRef != 1)
+ return;
+
+ if (bExportCpp2Uno)
+ {
+ uno_Mapping * pMapping = &aCpp2Uno;
+ ::uno_registerMapping(
+ &pMapping, freeMapping, &pCppEnv->aBase,
+ &pUnoEnv->aBase, nullptr );
+ }
+ else
+ {
+ uno_Mapping * pMapping = &aUno2Cpp;
+ ::uno_registerMapping(
+ &pMapping, freeMapping, &pUnoEnv->aBase,
+ &pCppEnv->aBase, nullptr );
+ }
+}
+
+void Bridge::release()
+{
+ if (! --nRef )
+ {
+ ::uno_revokeMapping( bExportCpp2Uno ? &aCpp2Uno : &aUno2Cpp );
+ }
+}
+
+Bridge::Bridge(
+ uno_ExtEnvironment * pCppEnv_, uno_ExtEnvironment * pUnoEnv_,
+ bool bExportCpp2Uno_)
+ : nRef( 1 )
+ , pCppEnv( pCppEnv_ )
+ , pUnoEnv( pUnoEnv_ )
+ , bExportCpp2Uno( bExportCpp2Uno_ )
+{
+ aCpp2Uno.pBridge = this;
+ aCpp2Uno.acquire = acquireMapping;
+ aCpp2Uno.release = releaseMapping;
+ aCpp2Uno.mapInterface = cpp2unoMapping;
+
+ aUno2Cpp.pBridge = this;
+ aUno2Cpp.acquire = acquireMapping;
+ aUno2Cpp.release = releaseMapping;
+ aUno2Cpp.mapInterface = uno2cppMapping;
+
+ (*pCppEnv->aBase.acquire)( &pCppEnv->aBase );
+ (*pUnoEnv->aBase.acquire)( &pUnoEnv->aBase );
+}
+
+Bridge::~Bridge()
+{
+ (*pUnoEnv->aBase.release)( &pUnoEnv->aBase );
+ (*pCppEnv->aBase.release)( &pCppEnv->aBase );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/component.cxx b/bridges/source/cpp_uno/shared/component.cxx
new file mode 100644
index 000000000..cef72d8b6
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/component.cxx
@@ -0,0 +1,224 @@
+/* -*- 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 <bridge.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <osl/mutex.hxx>
+#include <osl/time.h>
+#include <rtl/process.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <uno/environment.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.h>
+#include <cppu/EnvDcp.hxx>
+
+
+namespace {
+
+const OUString & cppu_cppenv_getStaticOIdPart()
+{
+ static OUString s_aStaticOidPart = []() {
+ OUStringBuffer aRet(64);
+ aRet.append("];");
+ // good guid
+ sal_uInt8 ar[16];
+ ::rtl_getGlobalProcessId(ar);
+ for (unsigned char i : ar)
+ {
+ aRet.append(static_cast<sal_Int32>(i), 16);
+ }
+ return aRet.makeStringAndClear();
+ }();
+ return s_aStaticOidPart;
+}
+
+}
+
+extern "C" {
+
+static void s_stub_computeObjectIdentifier(va_list * pParam)
+{
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ rtl_uString ** ppOId = va_arg(*pParam, rtl_uString **);
+ void * pInterface = va_arg(*pParam, void *);
+
+
+ assert(pEnv && ppOId && pInterface);
+ if (!(pEnv && ppOId && pInterface))
+ return;
+
+ if (*ppOId)
+ {
+ rtl_uString_release( *ppOId );
+ *ppOId = nullptr;
+ }
+
+ try
+ {
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::uno::XInterface > xHome(
+ static_cast< ::com::sun::star::uno::XInterface * >(
+ pInterface ),
+ ::com::sun::star::uno::UNO_QUERY );
+ assert(xHome.is() && "### query to XInterface failed!");
+ if (xHome.is())
+ {
+ // interface
+ OUString aRet =
+ OUString::number( reinterpret_cast< sal_Int64 >(xHome.get()), 16 ) +
+ ";" +
+ // ;environment[context]
+ OUString::unacquired(&pEnv->aBase.pTypeName) +
+ "[" +
+ OUString::number( reinterpret_cast< sal_Int64 >(pEnv->aBase.pContext), 16 ) +
+ // ];good guid
+ cppu_cppenv_getStaticOIdPart();
+ *ppOId = aRet.pData;
+ ::rtl_uString_acquire( *ppOId );
+ }
+ }
+ catch (const ::com::sun::star::uno::RuntimeException & e)
+ {
+ SAL_WARN("bridges",
+ "### RuntimeException occurred during queryInterface(): "
+ << e.Message);
+ }
+}
+
+static void computeObjectIdentifier(
+ uno_ExtEnvironment * pExtEnv, rtl_uString ** ppOId, void * pInterface )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_computeObjectIdentifier, pExtEnv, ppOId, pInterface);
+}
+
+static void s_stub_acquireInterface(va_list * pParam)
+{
+ /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *);
+ void * pCppI = va_arg(*pParam, void *);
+
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI )->acquire();
+}
+
+static void acquireInterface( uno_ExtEnvironment * pExtEnv, void * pCppI )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_acquireInterface, pExtEnv, pCppI);
+}
+
+static void s_stub_releaseInterface(va_list * pParam)
+{
+ /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *);
+ void * pCppI = va_arg(*pParam, void *);
+
+ static_cast< ::com::sun::star::uno::XInterface * >( pCppI )->release();
+}
+
+static void releaseInterface( uno_ExtEnvironment * pExtEnv, void * pCppI )
+{
+ uno_Environment_invoke(&pExtEnv->aBase, s_stub_releaseInterface, pExtEnv, pCppI);
+}
+
+static void environmentDisposing(
+ SAL_UNUSED_PARAMETER uno_Environment * )
+{
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_initEnvironment CPPU_ENV_uno_initEnvironment
+#endif
+
+SAL_DLLPUBLIC_EXPORT void uno_initEnvironment(uno_Environment * pCppEnv)
+ SAL_THROW_EXTERN_C()
+{
+ assert(pCppEnv->pExtEnv);
+ assert(
+ ::rtl_ustr_ascii_compare_WithLength(
+ pCppEnv->pTypeName->buffer, rtl_str_getLength(CPPU_CURRENT_LANGUAGE_BINDING_NAME), CPPU_CURRENT_LANGUAGE_BINDING_NAME )
+ == 0
+ && "### wrong environment type!");
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->computeObjectIdentifier
+ = computeObjectIdentifier;
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->acquireInterface = acquireInterface;
+ reinterpret_cast<uno_ExtEnvironment *>(pCppEnv)->releaseInterface = releaseInterface;
+ pCppEnv->environmentDisposing = environmentDisposing;
+}
+
+#ifdef DISABLE_DYNLOADING
+#define uno_ext_getMapping CPPU_ENV_uno_ext_getMapping
+#endif
+
+SAL_DLLPUBLIC_EXPORT void uno_ext_getMapping(
+ uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo)
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping && pFrom && pTo);
+ if (!(ppMapping && pFrom && pTo && pFrom->pExtEnv && pTo->pExtEnv))
+ return;
+
+ uno_Mapping * pMapping = nullptr;
+
+ OUString from_envTypeName(cppu::EnvDcp::getTypeName(pFrom->pTypeName));
+ OUString to_envTypeName(cppu::EnvDcp::getTypeName(pTo->pTypeName));
+
+ if (rtl_ustr_ascii_compare(
+ from_envTypeName.pData->buffer,
+ CPPU_CURRENT_LANGUAGE_BINDING_NAME ) == 0 &&
+ rtl_ustr_ascii_compare(
+ to_envTypeName.pData->buffer, UNO_LB_UNO ) == 0)
+ {
+ // ref count initially 1
+ pMapping = bridges::cpp_uno::shared::Bridge::createMapping(
+ pFrom->pExtEnv, pTo->pExtEnv, true );
+ ::uno_registerMapping(
+ &pMapping, bridges::cpp_uno::shared::freeMapping,
+ &pFrom->pExtEnv->aBase,
+ &pTo->pExtEnv->aBase, nullptr );
+ }
+ else if (rtl_ustr_ascii_compare(
+ to_envTypeName.pData->buffer,
+ CPPU_CURRENT_LANGUAGE_BINDING_NAME ) == 0 &&
+ rtl_ustr_ascii_compare(
+ from_envTypeName.pData->buffer, UNO_LB_UNO ) == 0)
+ {
+ // ref count initially 1
+ pMapping = bridges::cpp_uno::shared::Bridge::createMapping(
+ pTo->pExtEnv, pFrom->pExtEnv, false );
+ ::uno_registerMapping(
+ &pMapping, bridges::cpp_uno::shared::freeMapping,
+ &pFrom->pExtEnv->aBase,
+ &pTo->pExtEnv->aBase, nullptr );
+ }
+
+ if (*ppMapping)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ }
+ if (pMapping)
+ *ppMapping = pMapping;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx
new file mode 100644
index 000000000..dad1ad8f7
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx
@@ -0,0 +1,144 @@
+/* -*- 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 <cppinterfaceproxy.hxx>
+
+#include <bridge.hxx>
+#include <utility>
+#include <vtablefactory.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <typelib/typedescription.h>
+
+#include <cstddef>
+#include <memory>
+#include <new>
+
+namespace bridges::cpp_uno::shared {
+
+void freeCppInterfaceProxy(uno_ExtEnvironment * pEnv, void * pInterface)
+{
+ CppInterfaceProxy * pThis = CppInterfaceProxy::castInterfaceToProxy(
+ pInterface);
+ if (pEnv != pThis->pBridge->getCppEnv()) {
+ assert(false);
+ }
+
+ (*pThis->pBridge->getUnoEnv()->revokeInterface)(
+ pThis->pBridge->getUnoEnv(), pThis->pUnoI );
+ (*pThis->pUnoI->release)( pThis->pUnoI );
+ ::typelib_typedescription_release(
+ &pThis->pTypeDescr->aBase );
+ pThis->pBridge->release();
+
+#if OSL_DEBUG_LEVEL > 1
+ *(int *)pInterface = 0xdeadbabe;
+#endif
+ pThis->~CppInterfaceProxy();
+ delete[] reinterpret_cast< char * >(pThis);
+}
+
+com::sun::star::uno::XInterface * CppInterfaceProxy::create(
+ bridges::cpp_uno::shared::Bridge * pBridge, uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr, OUString const & rOId)
+{
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&pTypeDescr));
+ static bridges::cpp_uno::shared::VtableFactory factory;
+ const bridges::cpp_uno::shared::VtableFactory::Vtables& rVtables(
+ factory.getVtables(pTypeDescr));
+ std::unique_ptr< char[] > pMemory(
+ new char[
+ sizeof (CppInterfaceProxy)
+ + (rVtables.count - 1) * sizeof (void **)]);
+ new(pMemory.get()) CppInterfaceProxy(pBridge, pUnoI, pTypeDescr, rOId);
+ CppInterfaceProxy * pProxy = reinterpret_cast< CppInterfaceProxy * >(
+ pMemory.release());
+ for (sal_Int32 i = 0; i < rVtables.count; ++i) {
+ pProxy->vtables[i] = VtableFactory::mapBlockToVtable(
+ rVtables.blocks[i].start);
+ }
+ return castProxyToInterface(pProxy);
+}
+
+void CppInterfaceProxy::acquireProxy()
+{
+ if (++nRef == 1)
+ {
+ // rebirth of proxy zombie
+ // register at cpp env
+ void * pThis = castProxyToInterface( this );
+ (*pBridge->getCppEnv()->registerProxyInterface)(
+ pBridge->getCppEnv(), &pThis, freeCppInterfaceProxy, oid.pData,
+ pTypeDescr );
+ assert(pThis == castProxyToInterface(this));
+ }
+}
+
+void CppInterfaceProxy::releaseProxy()
+{
+ if (! --nRef ) // last release
+ {
+ // revoke from cpp env
+ (*pBridge->getCppEnv()->revokeInterface)(
+ pBridge->getCppEnv(), castProxyToInterface( this ) );
+ }
+}
+
+CppInterfaceProxy::CppInterfaceProxy(
+ bridges::cpp_uno::shared::Bridge * pBridge_, uno_Interface * pUnoI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_, OUString aOId_)
+ : nRef( 1 )
+ , pBridge( pBridge_ )
+ , pUnoI( pUnoI_ )
+ , pTypeDescr( pTypeDescr_ )
+ , oid(std::move( aOId_ ))
+{
+ pBridge->acquire();
+ ::typelib_typedescription_acquire( &pTypeDescr->aBase );
+ (*pUnoI->acquire)( pUnoI );
+ (*pBridge->getUnoEnv()->registerInterface)(
+ pBridge->getUnoEnv(), reinterpret_cast< void ** >( &pUnoI ), oid.pData,
+ pTypeDescr );
+}
+
+CppInterfaceProxy::~CppInterfaceProxy()
+{}
+
+com::sun::star::uno::XInterface * CppInterfaceProxy::castProxyToInterface(
+ CppInterfaceProxy * pProxy)
+{
+ return reinterpret_cast< com::sun::star::uno::XInterface * >(
+ &pProxy->vtables);
+}
+
+CppInterfaceProxy * CppInterfaceProxy::castInterfaceToProxy(void * pInterface)
+{
+ // pInterface == &pProxy->vtables (this emulated offsetof is not truly
+ // portable):
+ char const * const base = reinterpret_cast< char const * >(16);
+ std::ptrdiff_t const offset = reinterpret_cast< char const * >(
+ &reinterpret_cast< CppInterfaceProxy const * >(base)->vtables) - base;
+ return reinterpret_cast< CppInterfaceProxy * >(
+ static_cast< char * >(pInterface) - offset);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/types.cxx b/bridges/source/cpp_uno/shared/types.cxx
new file mode 100644
index 000000000..61dc3dabe
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/types.cxx
@@ -0,0 +1,117 @@
+/* -*- 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 <types.hxx>
+
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+namespace bridges::cpp_uno::shared {
+
+bool isSimpleType(typelib_TypeClass typeClass) {
+ return typeClass <= typelib_TypeClass_DOUBLE
+ || typeClass == typelib_TypeClass_ENUM;
+}
+
+bool isSimpleType(typelib_TypeDescriptionReference const * type) {
+ return isSimpleType(type->eTypeClass);
+}
+
+bool isSimpleType(typelib_TypeDescription const * type) {
+ return isSimpleType(type->eTypeClass);
+}
+
+bool relatesToInterfaceType(typelib_TypeDescription const * type) {
+ switch (type->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_CompoundTypeDescription const * p
+ = reinterpret_cast< typelib_CompoundTypeDescription const * >(
+ type);
+ for (sal_Int32 i = 0; i < p->nMembers; ++i) {
+ switch (p->ppTypeRefs[i]->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ {
+ typelib_TypeDescription * t = nullptr;
+ TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
+ bool b = relatesToInterfaceType(t);
+ TYPELIB_DANGER_RELEASE(t);
+ if (b) {
+ return true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (p->pBaseTypeDescription != nullptr) {
+ return relatesToInterfaceType(&p->pBaseTypeDescription->aBase);
+ }
+ }
+ break;
+
+ case typelib_TypeClass_SEQUENCE:
+ switch (reinterpret_cast< typelib_IndirectTypeDescription const * >(
+ type)->pType->eTypeClass) {
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_SEQUENCE:
+ {
+ typelib_TypeDescription * t = nullptr;
+ TYPELIB_DANGER_GET(
+ &t,
+ reinterpret_cast< typelib_IndirectTypeDescription const * >(
+ type)->pType);
+ bool b = relatesToInterfaceType(t);
+ TYPELIB_DANGER_RELEASE(t);
+ return b;
+ }
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx
new file mode 100644
index 000000000..3c03c1cff
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx
@@ -0,0 +1,126 @@
+/* -*- 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 <unointerfaceproxy.hxx>
+
+#include <bridge.hxx>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <utility>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+
+namespace bridges::cpp_uno::shared {
+
+void freeUnoInterfaceProxy(uno_ExtEnvironment * pEnv, void * pProxy)
+{
+ UnoInterfaceProxy * pThis =
+ static_cast< UnoInterfaceProxy * >(
+ static_cast< uno_Interface * >( pProxy ) );
+ if (pEnv != pThis->pBridge->getUnoEnv()) {
+ assert(false);
+ }
+
+ (*pThis->pBridge->getCppEnv()->revokeInterface)(
+ pThis->pBridge->getCppEnv(), pThis->pCppI );
+ pThis->pCppI->release();
+ ::typelib_typedescription_release(&pThis->pTypeDescr->aBase);
+ pThis->pBridge->release();
+
+#if OSL_DEBUG_LEVEL > 1
+ *(int *)pProxy = 0xdeadbabe;
+#endif
+ delete pThis;
+}
+
+void acquireProxy(uno_Interface * pUnoI)
+{
+ if (++static_cast< UnoInterfaceProxy * >( pUnoI )->nRef != 1)
+ return;
+
+ // rebirth of proxy zombie
+ // register at uno env
+#if OSL_DEBUG_LEVEL > 1
+ void * pThis = pUnoI;
+#endif
+ (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()->
+ registerProxyInterface)(
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(),
+ reinterpret_cast< void ** >( &pUnoI ), freeUnoInterfaceProxy,
+ static_cast< UnoInterfaceProxy * >( pUnoI )->oid.pData,
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pTypeDescr );
+#if OSL_DEBUG_LEVEL > 1
+ assert(pThis == pUnoI);
+#endif
+}
+
+void releaseProxy(uno_Interface * pUnoI)
+{
+ if (! --static_cast< UnoInterfaceProxy * >( pUnoI )->nRef )
+ {
+ // revoke from uno env on last release
+ (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()->
+ revokeInterface)(
+ static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(),
+ pUnoI );
+ }
+}
+
+UnoInterfaceProxy * UnoInterfaceProxy::create(
+ bridges::cpp_uno::shared::Bridge * pBridge,
+ com::sun::star::uno::XInterface * pCppI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId)
+{
+ return new UnoInterfaceProxy(pBridge, pCppI, pTypeDescr, rOId);
+}
+
+UnoInterfaceProxy::UnoInterfaceProxy(
+ bridges::cpp_uno::shared::Bridge * pBridge_,
+ com::sun::star::uno::XInterface * pCppI_,
+ typelib_InterfaceTypeDescription * pTypeDescr_, OUString aOId_)
+ : nRef( 1 )
+ , pBridge( pBridge_ )
+ , pCppI( pCppI_ )
+ , pTypeDescr( pTypeDescr_ )
+ , oid(std::move( aOId_ ))
+{
+ pBridge->acquire();
+ ::typelib_typedescription_acquire(&pTypeDescr->aBase);
+ if (!pTypeDescr->aBase.bComplete)
+ ::typelib_typedescription_complete(
+ reinterpret_cast<typelib_TypeDescription **>(&pTypeDescr));
+ assert(pTypeDescr->aBase.bComplete);
+ pCppI->acquire();
+ (*pBridge->getCppEnv()->registerInterface)(
+ pBridge->getCppEnv(), reinterpret_cast< void ** >( &pCppI ), oid.pData,
+ pTypeDescr );
+
+ // uno_Interface
+ acquire = acquireProxy;
+ release = releaseProxy;
+ pDispatcher = unoInterfaceProxyDispatch;
+}
+
+UnoInterfaceProxy::~UnoInterfaceProxy()
+{}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/vtablefactory.cxx b/bridges/source/cpp_uno/shared/vtablefactory.cxx
new file mode 100644
index 000000000..53b516cde
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/vtablefactory.cxx
@@ -0,0 +1,403 @@
+/* -*- 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 <vtablefactory.hxx>
+
+#include <vtables.hxx>
+
+#include <osl/thread.h>
+#include <osl/security.hxx>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/alloc.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.hxx>
+
+#include <memory>
+#include <new>
+#include <unordered_map>
+#include <vector>
+
+#if defined SAL_UNX
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#elif defined _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#error Unsupported platform
+#endif
+
+#if defined USE_DOUBLE_MMAP
+#include <fcntl.h>
+#endif
+
+#if defined MACOSX && defined __aarch64__
+#include <pthread.h>
+#endif
+
+using bridges::cpp_uno::shared::VtableFactory;
+
+namespace {
+
+extern "C" void * allocExec(
+ SAL_UNUSED_PARAMETER rtl_arena_type *, sal_Size * size)
+{
+ std::size_t pagesize;
+#if defined SAL_UNX
+#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY || defined HAIKU
+ pagesize = getpagesize();
+#else
+ pagesize = sysconf(_SC_PAGESIZE);
+#endif
+#elif defined _WIN32
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ pagesize = info.dwPageSize;
+#else
+#error Unsupported platform
+#endif
+ std::size_t n = (*size + (pagesize - 1)) & ~(pagesize - 1);
+ void * p;
+#if defined SAL_UNX
+#if defined MACOSX
+ p = mmap(
+ nullptr, n, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1,
+ 0);
+ if (p != MAP_FAILED) {
+ goto done;
+ }
+ {
+ auto const e = errno;
+ SAL_INFO("bridges.osx", "mmap failed with " << e);
+ if (e != EINVAL) {
+ p = nullptr;
+ goto done;
+ }
+ }
+ // At least some macOS 10.13 machines are reported to fail the above mmap with EINVAL (see
+ // tdf#134754 "Crash on macOS 10.13 opening local HSQLDB-based odb file in Base on LibreOffice 7
+ // rc1", so in that case retry with the "traditional" approach:
+#endif
+ p = mmap(
+ nullptr, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
+ 0);
+ if (p == MAP_FAILED) {
+ p = nullptr;
+ }
+ else if (mprotect (p, n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
+ {
+ munmap (p, n);
+ p = nullptr;
+ }
+#if defined MACOSX
+done:
+#endif
+#elif defined _WIN32
+ p = VirtualAlloc(nullptr, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+#endif
+ if (p != nullptr) {
+ *size = n;
+ }
+ return p;
+}
+
+extern "C" void freeExec(
+ SAL_UNUSED_PARAMETER rtl_arena_type *, void * address, sal_Size size)
+{
+#if defined SAL_UNX
+ munmap(address, size);
+#elif defined _WIN32
+ (void) size; // unused
+ VirtualFree(address, 0, MEM_RELEASE);
+#endif
+}
+
+#if defined MACOSX && defined __aarch64__
+struct JitMemoryProtectionGuard {
+ JitMemoryProtectionGuard() { pthread_jit_write_protect_np(0); }
+ ~JitMemoryProtectionGuard() { pthread_jit_write_protect_np(1); }
+};
+#endif
+
+}
+
+class VtableFactory::GuardedBlocks:
+ public std::vector<Block>
+{
+public:
+ GuardedBlocks(const GuardedBlocks&) = delete;
+ const GuardedBlocks& operator=(const GuardedBlocks&) = delete;
+
+ explicit GuardedBlocks(VtableFactory const & factory):
+ m_factory(factory), m_guarded(true) {}
+
+ ~GuardedBlocks();
+
+ void unguard() { m_guarded = false; }
+
+private:
+ VtableFactory const & m_factory;
+ bool m_guarded;
+};
+
+VtableFactory::GuardedBlocks::~GuardedBlocks() {
+ if (m_guarded) {
+ for (iterator i(begin()); i != end(); ++i) {
+ m_factory.freeBlock(*i);
+ }
+ }
+}
+
+class VtableFactory::BaseOffset {
+public:
+ explicit BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); }
+
+ sal_Int32 getFunctionOffset(OUString const & name) const
+ { return m_map.find(name)->second; }
+
+private:
+ sal_Int32 calculate(
+ typelib_InterfaceTypeDescription * type, sal_Int32 offset);
+
+ std::unordered_map< OUString, sal_Int32 > m_map;
+};
+
+sal_Int32 VtableFactory::BaseOffset::calculate(
+ typelib_InterfaceTypeDescription * type, sal_Int32 offset)
+{
+ OUString name(type->aBase.pTypeName);
+ if (m_map.find(name) == m_map.end()) {
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ offset = calculate(type->ppBaseTypes[i], offset);
+ }
+ m_map.insert({name, offset});
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ offset += bridges::cpp_uno::shared::getLocalFunctions(type);
+ }
+ return offset;
+}
+
+VtableFactory::VtableFactory(): m_arena(
+ rtl_arena_create(
+ "bridges::cpp_uno::shared::VtableFactory",
+ sizeof (void *), // to satisfy alignment requirements
+ 0, nullptr, allocExec, freeExec, 0))
+{
+ if (m_arena == nullptr) {
+ throw std::bad_alloc();
+ }
+}
+
+VtableFactory::~VtableFactory() {
+ {
+ std::scoped_lock guard(m_mutex);
+ for (const auto& rEntry : m_map) {
+ for (sal_Int32 j = 0; j < rEntry.second.count; ++j) {
+ freeBlock(rEntry.second.blocks[j]);
+ }
+ }
+ }
+ rtl_arena_destroy(m_arena);
+}
+
+const VtableFactory::Vtables& VtableFactory::getVtables(
+ typelib_InterfaceTypeDescription * type)
+{
+ OUString name(type->aBase.pTypeName);
+ std::scoped_lock guard(m_mutex);
+ Map::iterator i(m_map.find(name));
+ if (i == m_map.end()) {
+ GuardedBlocks blocks(*this);
+ createVtables(blocks, BaseOffset(type), type, 0, type, true);
+ Vtables vtables;
+ assert(blocks.size() <= SAL_MAX_INT32);
+ vtables.count = static_cast< sal_Int32 >(blocks.size());
+ vtables.blocks.reset(new Block[vtables.count]);
+ for (sal_Int32 j = 0; j < vtables.count; ++j) {
+ vtables.blocks[j] = blocks[j];
+ }
+ i = m_map.emplace(name, std::move(vtables)).first;
+ blocks.unguard();
+ }
+ return i->second;
+}
+
+#ifdef USE_DOUBLE_MMAP
+bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
+{
+ std::size_t size = getBlockSize(slotCount);
+ std::size_t pagesize = sysconf(_SC_PAGESIZE);
+ block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
+ block.fd = -1;
+
+ // Try non-doublemmaped allocation first:
+ block.start = block.exec = rtl_arena_alloc(m_arena, &block.size);
+ if (block.start != nullptr) {
+ return true;
+ }
+
+ osl::Security aSecurity;
+ OUString strDirectory;
+ OUString strURLDirectory;
+ if (aSecurity.getHomeDir(strURLDirectory))
+ osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);
+
+ for (int i = strDirectory.isEmpty() ? 1 : 0; i < 2; ++i)
+ {
+ if (strDirectory.isEmpty())
+ strDirectory = "/tmp";
+
+ strDirectory += "/.execoooXXXXXX";
+ OString aTmpName = OUStringToOString(strDirectory, osl_getThreadTextEncoding());
+ std::unique_ptr<char[]> tmpfname(new char[aTmpName.getLength()+1]);
+ strncpy(tmpfname.get(), aTmpName.getStr(), aTmpName.getLength()+1);
+ // coverity[secure_temp] - https://communities.coverity.com/thread/3179
+ if ((block.fd = mkstemp(tmpfname.get())) == -1)
+ fprintf(stderr, "mkstemp(\"%s\") failed: %s\n", tmpfname.get(), strerror(errno));
+ if (block.fd == -1)
+ {
+ break;
+ }
+ unlink(tmpfname.get());
+ tmpfname.reset();
+#if defined(HAVE_POSIX_FALLOCATE)
+ int err = posix_fallocate(block.fd, 0, block.size);
+#else
+ int err = ftruncate(block.fd, block.size);
+#endif
+ if (err != 0)
+ {
+#if defined(HAVE_POSIX_FALLOCATE)
+ SAL_WARN("bridges", "posix_fallocate failed with code " << err);
+#else
+ SAL_WARN("bridges", "truncation of executable memory area failed with code " << err);
+#endif
+ close(block.fd);
+ block.fd = -1;
+ break;
+ }
+ block.start = mmap(nullptr, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
+ if (block.start== MAP_FAILED) {
+ block.start = nullptr;
+ }
+ block.exec = mmap(nullptr, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
+ if (block.exec == MAP_FAILED) {
+ block.exec = nullptr;
+ }
+
+ //All good
+ if (block.start && block.exec && block.fd != -1)
+ break;
+
+ freeBlock(block);
+
+ strDirectory.clear();
+ }
+ return (block.start != nullptr && block.exec != nullptr);
+}
+
+void VtableFactory::freeBlock(Block const & block) const {
+ //if the double-map failed we were allocated on the arena
+ if (block.fd == -1 && block.start == block.exec && block.start != nullptr)
+ rtl_arena_free(m_arena, block.start, block.size);
+ else
+ {
+ if (block.start) munmap(block.start, block.size);
+ if (block.exec) munmap(block.exec, block.size);
+ if (block.fd != -1) close(block.fd);
+ }
+}
+#else
+bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const
+{
+ block.size = getBlockSize(slotCount);
+ block.start = rtl_arena_alloc(m_arena, &block.size);
+ return block.start != nullptr;
+}
+
+void VtableFactory::freeBlock(Block const & block) const {
+ rtl_arena_free(m_arena, block.start, block.size);
+}
+#endif
+
+sal_Int32 VtableFactory::createVtables(
+ GuardedBlocks & blocks, BaseOffset const & baseOffset,
+ typelib_InterfaceTypeDescription * type, sal_Int32 vtableNumber,
+ typelib_InterfaceTypeDescription * mostDerived, bool includePrimary) const
+{
+ {
+#if defined MACOSX && defined __aarch64__
+ JitMemoryProtectionGuard guard;
+#endif
+ if (includePrimary) {
+ sal_Int32 slotCount
+ = bridges::cpp_uno::shared::getPrimaryFunctions(type);
+ Block block;
+ if (!createBlock(block, slotCount)) {
+ throw std::bad_alloc();
+ }
+ try {
+ Slot * slots = initializeBlock(
+ block.start, slotCount, vtableNumber, mostDerived);
+ unsigned char * codeBegin =
+ reinterpret_cast< unsigned char * >(slots);
+ unsigned char * code = codeBegin;
+ sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *);
+ for (typelib_InterfaceTypeDescription const * type2 = type;
+ type2 != nullptr; type2 = type2->pBaseTypeDescription)
+ {
+ code = addLocalFunctions(
+ &slots, code,
+#ifdef USE_DOUBLE_MMAP
+ reinterpret_cast<sal_uIntPtr>(block.exec) - reinterpret_cast<sal_uIntPtr>(block.start),
+#endif
+ type2,
+ baseOffset.getFunctionOffset(type2->aBase.pTypeName),
+ bridges::cpp_uno::shared::getLocalFunctions(type2),
+ vtableOffset);
+ }
+ flushCode(codeBegin, code);
+#ifdef USE_DOUBLE_MMAP
+ //Finished generating block, swap writable pointer with executable
+ //pointer
+ std::swap(block.start, block.exec);
+#endif
+ blocks.push_back(block);
+ } catch (...) {
+ freeBlock(block);
+ throw;
+ }
+ }
+ }
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ vtableNumber = createVtables(
+ blocks, baseOffset, type->ppBaseTypes[i],
+ vtableNumber + (i == 0 ? 0 : 1), mostDerived, i != 0);
+ }
+ return vtableNumber;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/shared/vtables.cxx b/bridges/source/cpp_uno/shared/vtables.cxx
new file mode 100644
index 000000000..9a7d7b376
--- /dev/null
+++ b/bridges/source/cpp_uno/shared/vtables.cxx
@@ -0,0 +1,146 @@
+/* -*- 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 <vtables.hxx>
+
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+
+#include <algorithm>
+#include <cassert>
+
+namespace
+{
+
+/**
+ * Calculates the number of vtables associated with an interface type.
+ *
+ * <p>Multiple-inheritance C++ classes have more than one vtable.</p>
+ *
+ * @param type a non-null pointer to an interface type description
+ * @return the number of vtables associated with the given interface type
+ */
+sal_Int32 getVtableCount(typelib_InterfaceTypeDescription const * type) {
+ sal_Int32 n = 0;
+ for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) {
+ n += getVtableCount(type->ppBaseTypes[i]);
+ }
+ return std::max< sal_Int32 >(n, 1);
+}
+
+/**
+ * Maps a local member index to a local function index.
+ *
+ * <p><em>Local</em> members/functions are those not inherited from any base
+ * types. The number of <em>functions</em> is potentially larger than the
+ * number of <em>members</em>, as each read&ndash;write attribute member counts
+ * as two functions.</p>
+ *
+ * @param type a non-null pointer to an interface type description
+ * @param localMember a local member index, relative to the given interface type
+ * @return the local function index corresponding to the given local member
+ * index, relative to the given interface type
+ */
+sal_Int32 mapLocalMemberToLocalFunction(
+ typelib_InterfaceTypeDescription * type, sal_Int32 localMember)
+{
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ sal_Int32 localMemberOffset = type->nAllMembers - type->nMembers;
+ sal_Int32 localFunctionOffset = type->nMapFunctionIndexToMemberIndex
+ - bridges::cpp_uno::shared::getLocalFunctions(type);
+ return type->pMapMemberIndexToFunctionIndex[localMemberOffset + localMember]
+ - localFunctionOffset;
+}
+
+// Since on Solaris we compile with --instances=static, getVtableSlot cannot be
+// a template function, with explicit instantiates for
+// T = typelib_InterfaceAttributeTypeDescription and
+// T = typelib_InterfaceMethodTypeDescription in this file; hence, there are two
+// overloaded versions of getVtableSlot that both delegate to this template
+// function:
+template< typename T > bridges::cpp_uno::shared::VtableSlot doGetVtableSlot(
+ T const * ifcMember)
+{
+ bridges::cpp_uno::shared::VtableSlot slot;
+ slot.offset = 0;
+ T * member = const_cast< T * >(ifcMember);
+ while (member->pBaseRef != nullptr) {
+ assert(member->nIndex < member->pInterface->nBaseTypes);
+ for (sal_Int32 i = 0; i < member->nIndex; ++i) {
+ slot.offset += getVtableCount(member->pInterface->ppBaseTypes[i]);
+ }
+ typelib_TypeDescription * desc = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ &desc, member->pBaseRef);
+ assert(
+ desc != nullptr && desc->eTypeClass == member->aBase.aBase.eTypeClass);
+ if (member != ifcMember) {
+ typelib_typedescription_release(&member->aBase.aBase);
+ }
+ member = reinterpret_cast< T * >(desc);
+ }
+ slot.index
+ = bridges::cpp_uno::shared::getPrimaryFunctions(
+ member->pInterface->pBaseTypeDescription)
+ + mapLocalMemberToLocalFunction(member->pInterface, member->nIndex);
+ if (member != ifcMember) {
+ typelib_typedescription_release(&member->aBase.aBase);
+ }
+ return slot;
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const * type) {
+ return type->nMembers == 0
+ ? 0
+ : (type->nMapFunctionIndexToMemberIndex
+ - type->pMapMemberIndexToFunctionIndex[
+ type->nAllMembers - type->nMembers]);
+}
+
+sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription * type) {
+ sal_Int32 n = 0;
+ for (; type != nullptr; type = type->pBaseTypeDescription) {
+ typelib_typedescription_complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&type));
+ n += getLocalFunctions(type);
+ }
+ return n;
+}
+
+VtableSlot getVtableSlot(
+ typelib_InterfaceAttributeTypeDescription const * ifcMember)
+{
+ return doGetVtableSlot(ifcMember);
+}
+
+VtableSlot getVtableSlot(
+ typelib_InterfaceMethodTypeDescription const * ifcMember)
+{
+ return doGetVtableSlot(ifcMember);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */