summaryrefslogtreecommitdiffstats
path: root/cppu/source
diff options
context:
space:
mode:
Diffstat (limited to 'cppu/source')
-rw-r--r--cppu/source/AffineBridge/AffineBridge.cxx360
-rw-r--r--cppu/source/LogBridge/LogBridge.cxx262
-rw-r--r--cppu/source/UnsafeBridge/UnsafeBridge.cxx144
-rw-r--r--cppu/source/cppu/compat.cxx47
-rw-r--r--cppu/source/cppu/cppu_opt.cxx66
-rw-r--r--cppu/source/helper/purpenv/Proxy.hxx76
-rw-r--r--cppu/source/helper/purpenv/helper_purpenv_Environment.cxx522
-rw-r--r--cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx215
-rw-r--r--cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx504
-rw-r--r--cppu/source/threadpool/current.cxx210
-rw-r--r--cppu/source/threadpool/current.hxx47
-rw-r--r--cppu/source/threadpool/jobqueue.cxx177
-rw-r--r--cppu/source/threadpool/jobqueue.hxx72
-rw-r--r--cppu/source/threadpool/thread.cxx198
-rw-r--r--cppu/source/threadpool/thread.hxx67
-rw-r--r--cppu/source/threadpool/threadident.cxx120
-rw-r--r--cppu/source/threadpool/threadpool.cxx476
-rw-r--r--cppu/source/threadpool/threadpool.hxx162
-rw-r--r--cppu/source/typelib/static_types.cxx555
-rw-r--r--cppu/source/typelib/typelib.cxx2399
-rw-r--r--cppu/source/typelib/typelib.hxx45
-rw-r--r--cppu/source/uno/EnvDcp.cxx43
-rw-r--r--cppu/source/uno/EnvStack.cxx382
-rw-r--r--cppu/source/uno/IdentityMapping.cxx105
-rw-r--r--cppu/source/uno/IdentityMapping.hxx31
-rw-r--r--cppu/source/uno/any.cxx142
-rw-r--r--cppu/source/uno/assign.hxx449
-rw-r--r--cppu/source/uno/cascade_mapping.cxx308
-rw-r--r--cppu/source/uno/cascade_mapping.hxx32
-rw-r--r--cppu/source/uno/check.cxx335
-rw-r--r--cppu/source/uno/constr.hxx138
-rw-r--r--cppu/source/uno/copy.hxx655
-rw-r--r--cppu/source/uno/data.cxx316
-rw-r--r--cppu/source/uno/destr.hxx352
-rw-r--r--cppu/source/uno/eq.hxx635
-rw-r--r--cppu/source/uno/lbenv.cxx1147
-rw-r--r--cppu/source/uno/lbmap.cxx754
-rw-r--r--cppu/source/uno/loadmodule.cxx75
-rw-r--r--cppu/source/uno/loadmodule.hxx47
-rw-r--r--cppu/source/uno/prim.hxx153
-rw-r--r--cppu/source/uno/sequence.cxx912
41 files changed, 13735 insertions, 0 deletions
diff --git a/cppu/source/AffineBridge/AffineBridge.cxx b/cppu/source/AffineBridge/AffineBridge.cxx
new file mode 100644
index 000000000..3e2b01df1
--- /dev/null
+++ b/cppu/source/AffineBridge/AffineBridge.cxx
@@ -0,0 +1,360 @@
+/* -*- 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/thread.hxx>
+#include <osl/conditn.hxx>
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <cppu/Enterable.hxx>
+#include <cppu/helper/purpenv/Environment.hxx>
+#include <cppu/helper/purpenv/Mapping.hxx>
+#include <memory>
+
+namespace {
+
+class InnerThread;
+class OuterThread;
+
+class AffineBridge : public cppu::Enterable
+{
+public:
+ enum Msg
+ {
+ CB_DONE,
+ CB_FPOINTER
+ };
+
+ Msg m_message;
+ uno_EnvCallee * m_pCallee;
+ va_list * m_pParam;
+
+ osl::Mutex m_innerMutex;
+ oslThreadIdentifier m_innerThreadId;
+ std::unique_ptr<InnerThread> m_pInnerThread;
+ osl::Condition m_innerCondition;
+ sal_Int32 m_enterCount;
+
+ osl::Mutex m_outerMutex;
+ oslThreadIdentifier m_outerThreadId;
+ osl::Condition m_outerCondition;
+ std::unique_ptr<OuterThread> m_pOuterThread;
+
+ explicit AffineBridge();
+ virtual ~AffineBridge() override;
+
+ virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override;
+ virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override;
+
+ virtual void v_enter() override;
+ virtual void v_leave() override;
+
+ virtual bool v_isValid(OUString * pReason) override;
+
+ void innerDispatch();
+ void outerDispatch(bool loop);
+};
+
+class InnerThread : public osl::Thread
+{
+ virtual void SAL_CALL run() override;
+
+ AffineBridge * m_pAffineBridge;
+
+public:
+ explicit InnerThread(AffineBridge * threadEnvironment)
+ : m_pAffineBridge(threadEnvironment)
+ {
+ create();
+ }
+};
+
+}
+
+void InnerThread::run()
+{
+ osl_setThreadName("UNO AffineBridge InnerThread");
+
+ m_pAffineBridge->enter();
+ m_pAffineBridge->innerDispatch();
+ m_pAffineBridge->leave();
+}
+
+namespace {
+
+class OuterThread : public osl::Thread
+{
+ virtual void SAL_CALL run() override;
+
+ AffineBridge * m_pAffineBridge;
+
+public:
+ explicit OuterThread(AffineBridge * threadEnvironment);
+};
+
+}
+
+OuterThread::OuterThread(AffineBridge * threadEnvironment)
+ : m_pAffineBridge(threadEnvironment)
+{
+ create();
+}
+
+void OuterThread::run()
+{
+ osl_setThreadName("UNO AffineBridge OuterThread");
+
+ osl::MutexGuard guard(m_pAffineBridge->m_outerMutex);
+
+ m_pAffineBridge->m_outerThreadId = getIdentifier();
+ m_pAffineBridge->outerDispatch(false);
+ m_pAffineBridge->m_outerThreadId = 0;
+
+ m_pAffineBridge->m_pOuterThread = nullptr;
+ m_pAffineBridge = nullptr;
+}
+
+
+AffineBridge::AffineBridge()
+ : m_message (CB_DONE),
+ m_pCallee (nullptr),
+ m_pParam (nullptr),
+ m_innerThreadId(0),
+ m_enterCount (0),
+ m_outerThreadId(0)
+{
+ SAL_INFO("cppu.affinebridge", "LIFE: AffineBridge::AffineBridge(uno_Environment * pEnv) -> " << this);
+}
+
+AffineBridge::~AffineBridge()
+{
+ SAL_INFO("cppu.affinebridge", "LIFE: AffineBridge::~AffineBridge() -> " << this);
+
+ if (m_pInnerThread && osl::Thread::getCurrentIdentifier() != m_innerThreadId)
+ {
+ m_message = CB_DONE;
+ m_innerCondition.set();
+
+ m_pInnerThread->join();
+ }
+
+ m_pInnerThread.reset();
+
+ if (m_pOuterThread)
+ {
+ m_pOuterThread->join();
+ }
+}
+
+
+void AffineBridge::outerDispatch(bool loop)
+{
+ OSL_ASSERT(m_outerThreadId == osl::Thread::getCurrentIdentifier());
+ OSL_ASSERT(m_innerThreadId != m_outerThreadId);
+
+ Msg mm;
+
+ do
+ {
+ // FIXME: created outer thread must not wait
+ // in case of no message
+ // note: no message can happen in case newly created
+ // outer thread acquire outerMutex after a real outer
+ // thread enters outerDispatch!
+ m_outerCondition.wait();
+ m_outerCondition.reset();
+
+ mm = m_message;
+
+ switch(mm)
+ {
+ case CB_DONE:
+ break;
+
+ case CB_FPOINTER:
+ {
+ m_pCallee(m_pParam);
+
+ m_message = CB_DONE;
+ m_innerCondition.set();
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+ while(mm != CB_DONE && loop);
+}
+
+void AffineBridge::innerDispatch()
+{
+ OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
+ OSL_ASSERT(m_innerThreadId != m_outerThreadId);
+
+ Msg mm;
+
+ do
+ {
+ m_innerCondition.wait();
+ m_innerCondition.reset();
+
+ mm = m_message;
+
+ switch(mm)
+ {
+ case CB_DONE:
+ break;
+
+ case CB_FPOINTER:
+ {
+ m_pCallee(m_pParam);
+
+ m_message = CB_DONE;
+ m_outerCondition.set();
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+ while(mm != CB_DONE);
+}
+
+void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into
+
+ if (m_innerThreadId == 0) // no inner thread yet
+ {
+ m_pInnerThread.reset(new InnerThread(this));
+ }
+
+ bool bResetId = false;
+ if (!m_outerThreadId)
+ {
+ m_outerThreadId = osl::Thread::getCurrentIdentifier();
+ bResetId = true;
+ }
+
+ m_message = CB_FPOINTER;
+ m_pCallee = pCallee;
+ m_pParam = pParam;
+ m_innerCondition.set();
+
+ outerDispatch(true);
+
+ if (bResetId)
+ m_outerThreadId = 0;
+}
+
+void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ OSL_ASSERT(m_innerThreadId);
+
+ osl::MutexGuard guard(m_innerMutex);
+
+ if (m_outerThreadId == 0) // no outer thread yet
+ {
+ osl::MutexGuard guard_m_outerMutex(m_outerMutex);
+
+ if (m_outerThreadId == 0)
+ {
+ if (m_pOuterThread)
+ {
+ m_pOuterThread->join();
+ }
+
+ m_pOuterThread.reset(new OuterThread(this));
+ }
+ }
+
+ m_message = CB_FPOINTER;
+ m_pCallee = pCallee;
+ m_pParam = pParam;
+ m_outerCondition.set();
+
+ innerDispatch();
+}
+
+void AffineBridge::v_enter()
+{
+ m_innerMutex.acquire();
+
+ if (!m_enterCount)
+ m_innerThreadId = osl::Thread::getCurrentIdentifier();
+
+ OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
+
+ ++ m_enterCount;
+}
+
+void AffineBridge::v_leave()
+{
+ OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier());
+
+ -- m_enterCount;
+ if (!m_enterCount)
+ m_innerThreadId = 0;
+
+ m_innerMutex.release();
+}
+
+bool AffineBridge::v_isValid(OUString * pReason)
+{
+ bool result = m_enterCount > 0;
+ if (!result)
+ *pReason = "not entered";
+
+ else
+ {
+ result = m_innerThreadId == osl::Thread::getCurrentIdentifier();
+
+ if (!result)
+ *pReason = "wrong thread";
+ }
+
+ if (result)
+ *pReason = "OK";
+
+ return result;
+}
+
+#ifdef DISABLE_DYNLOADING
+
+#define uno_initEnvironment affine_uno_uno_initEnvironment
+#define uno_ext_getMapping affine_uno_uno_ext_getMapping
+
+#endif
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv)
+ SAL_THROW_EXTERN_C()
+{
+ cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge());
+}
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo )
+{
+ cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/LogBridge/LogBridge.cxx b/cppu/source/LogBridge/LogBridge.cxx
new file mode 100644
index 000000000..b93b43b64
--- /dev/null
+++ b/cppu/source/LogBridge/LogBridge.cxx
@@ -0,0 +1,262 @@
+/* -*- 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 <osl/thread.h>
+#include <osl/thread.hxx>
+#include <osl/diagnose.h>
+#include <cppu/Enterable.hxx>
+#include <cppu/helper/purpenv/Environment.hxx>
+#include <cppu/helper/purpenv/Mapping.hxx>
+#include <com/sun/star/uno/Type.hxx>
+#include <sal/log.hxx>
+
+namespace
+{
+class LogBridge : public cppu::Enterable
+{
+ osl::Mutex m_mutex;
+ sal_Int32 m_count;
+ oslThreadIdentifier m_threadId;
+
+ virtual ~LogBridge() override;
+
+public:
+ explicit LogBridge();
+
+ virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override;
+ virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override;
+
+ virtual void v_enter() override;
+ virtual void v_leave() override;
+
+ virtual bool v_isValid(OUString * pReason) override;
+};
+
+LogBridge::LogBridge()
+ : m_count (0)
+ ,m_threadId(0)
+{
+}
+
+LogBridge::~LogBridge()
+{
+ OSL_ASSERT(m_count >= 0);
+}
+
+void LogBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ enter();
+ pCallee(pParam);
+ leave();
+}
+
+void LogBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ OSL_ASSERT(m_count > 0);
+
+ -- m_count;
+ pCallee(pParam);
+ ++ m_count;
+
+ if (!m_threadId)
+ m_threadId = osl::Thread::getCurrentIdentifier();
+}
+
+void LogBridge::v_enter()
+{
+ m_mutex.acquire();
+
+ OSL_ASSERT(m_count >= 0);
+
+ if (m_count == 0)
+ m_threadId = osl::Thread::getCurrentIdentifier();
+
+ ++ m_count;
+}
+
+void LogBridge::v_leave()
+{
+ OSL_ASSERT(m_count > 0);
+
+ -- m_count;
+ if (!m_count)
+ m_threadId = 0;
+
+
+ m_mutex.release();
+}
+
+bool LogBridge::v_isValid(OUString * pReason)
+{
+ bool result = m_count > 0;
+ if (!result)
+ {
+ *pReason = "not entered";
+ }
+ else
+ {
+ result = m_threadId == osl::Thread::getCurrentIdentifier();
+
+ if (!result)
+ *pReason = "wrong thread";
+ }
+
+ if (result)
+ *pReason = "OK";
+
+ return result;
+}
+
+ void traceValue(typelib_TypeDescriptionReference* _pTypeRef,void* pArg)
+ {
+ switch(_pTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_STRING:
+ SAL_INFO("cppu.log", "" << *static_cast< OUString*>(pArg));
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ SAL_INFO("cppu.log", "" << *static_cast<sal_Bool*>(pArg));
+ break;
+ case typelib_TypeClass_BYTE:
+ SAL_INFO("cppu.log", "" << *static_cast<sal_Int8*>(pArg));
+ break;
+ case typelib_TypeClass_CHAR:
+ SAL_INFO("cppu.log", "" << *static_cast<char*>(pArg));
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ SAL_INFO("cppu.log", "" << *static_cast<sal_Int16*>(pArg));
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ SAL_INFO("cppu.log", "" << *static_cast<sal_Int32*>(pArg));
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ SAL_INFO("cppu.log", "" << *static_cast<sal_Int64*>(pArg));
+ break;
+ case typelib_TypeClass_FLOAT:
+ SAL_INFO("cppu.log", "" << *static_cast<float*>(pArg));
+ break;
+ case typelib_TypeClass_DOUBLE:
+ SAL_INFO("cppu.log", "" << *static_cast<double*>(pArg));
+ break;
+ case typelib_TypeClass_TYPE:
+ SAL_INFO("cppu.log", "" << static_cast<css::uno::Type*>(pArg)->getTypeName());
+ break;
+ case typelib_TypeClass_ANY:
+ if ( static_cast<uno_Any*>(pArg)->pData )
+ traceValue(static_cast<uno_Any*>(pArg)->pType,static_cast<uno_Any*>(pArg)->pData);
+ else
+ SAL_INFO("cppu.log", "void");
+ break;
+ case typelib_TypeClass_EXCEPTION:
+ SAL_INFO("cppu.log", "exception");
+ break;
+ case typelib_TypeClass_INTERFACE:
+ SAL_INFO("cppu.log", "" << _pTypeRef->pTypeName << "0x" << std::hex << pArg);
+ break;
+ case typelib_TypeClass_VOID:
+ SAL_INFO("cppu.log", "void");
+ break;
+ default:
+ SAL_INFO("cppu.log", "0x" << std::hex << pArg);
+ break;
+ } // switch(pParams[i].pTypeRef->eTypeClass)
+ }
+}
+
+static void LogProbe(
+ bool pre,
+ SAL_UNUSED_PARAMETER void * /*pThis*/,
+ SAL_UNUSED_PARAMETER void * /*pContext*/,
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ typelib_MethodParameter * pParams,
+ sal_Int32 nParams,
+ typelib_TypeDescription const * pMemberType,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException )
+{
+ OString sTemp;
+ if ( pMemberType && pMemberType->pTypeName )
+ sTemp = OUStringToOString(
+ OUString::unacquired(&pMemberType->pTypeName),RTL_TEXTENCODING_ASCII_US);
+ if ( pre )
+ {
+ SAL_INFO("cppu.log", "{ LogBridge () " << sTemp );
+ if ( nParams )
+ {
+ SAL_INFO("cppu.log", "\n| : ( LogBridge ");
+ for(sal_Int32 i = 0;i < nParams;++i)
+ {
+ if ( i > 0 )
+ SAL_INFO("cppu.log", ",");
+ traceValue(pParams[i].pTypeRef,pArgs[i]);
+
+ }
+ SAL_INFO("cppu.log", ")");
+ } // if ( nParams )
+ SAL_INFO("cppu.log", "\n");
+ }
+ else if ( !pre )
+ {
+ SAL_INFO("cppu.log", "} LogBridge () " << sTemp);
+ if ( ppException && *ppException )
+ {
+ SAL_INFO("cppu.log", " exception occurred : ");
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, (*ppException)->pType );
+ SAL_INFO("cppu.log", "" << pElementTypeDescr->pTypeName);
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ }
+ else if ( pReturnTypeRef )
+ {
+ SAL_INFO("cppu.log", " return : ");
+ traceValue(pReturnTypeRef,pReturn);
+ } // if ( pReturn && pReturnTypeRef )
+
+ SAL_INFO("cppu.log", "\n");
+ }
+}
+
+#ifdef DISABLE_DYNLOADING
+
+#define uno_initEnvironment log_uno_uno_initEnvironment
+#define uno_ext_getMapping log_uno_uno_ext_getMapping
+
+#endif
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv)
+ SAL_THROW_EXTERN_C()
+{
+ cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new LogBridge());
+}
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo )
+{
+ cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo,LogProbe);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/UnsafeBridge/UnsafeBridge.cxx b/cppu/source/UnsafeBridge/UnsafeBridge.cxx
new file mode 100644
index 000000000..491a888c3
--- /dev/null
+++ b/cppu/source/UnsafeBridge/UnsafeBridge.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 <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <osl/thread.hxx>
+#include <sal/log.hxx>
+
+#include <cppu/Enterable.hxx>
+#include <cppu/helper/purpenv/Environment.hxx>
+#include <cppu/helper/purpenv/Mapping.hxx>
+
+namespace {
+
+class UnsafeBridge : public cppu::Enterable
+{
+ osl::Mutex m_mutex;
+ sal_Int32 m_count;
+ oslThreadIdentifier m_threadId;
+
+ virtual ~UnsafeBridge() override;
+
+public:
+ explicit UnsafeBridge();
+
+ virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override;
+ virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override;
+
+ virtual void v_enter() override;
+ virtual void v_leave() override;
+
+ virtual bool v_isValid(OUString * pReason) override;
+};
+
+}
+
+UnsafeBridge::UnsafeBridge()
+ : m_count (0),
+ m_threadId(0)
+{
+ SAL_INFO("cppu.unsafebridge", "LIFE: UnsafeBridge::UnsafeBridge(uno_Environment * pEnv) -> " << this);
+}
+
+UnsafeBridge::~UnsafeBridge()
+{
+ SAL_INFO("cppu.unsafebridge", "LIFE: UnsafeBridge::~UnsafeBridge() -> " << this);
+
+ SAL_WARN_IF(m_count < 0, "cppu.unsafebridge", "m_count is less than 0");
+}
+
+void UnsafeBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ enter();
+ pCallee(pParam);
+ leave();
+}
+
+void UnsafeBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ SAL_WARN_IF(m_count <= 0, "cppu.unsafebridge", "m_count is less than or equal to 0");
+
+ -- m_count;
+ pCallee(pParam);
+ ++ m_count;
+
+ if (!m_threadId)
+ m_threadId = osl::Thread::getCurrentIdentifier();
+}
+
+void UnsafeBridge::v_enter()
+{
+ m_mutex.acquire();
+
+ SAL_WARN_IF(m_count < 0, "cppu.unsafebridge", "m_count is less than 0");
+
+ if (m_count == 0)
+ m_threadId = osl::Thread::getCurrentIdentifier();
+
+ ++ m_count;
+}
+
+void UnsafeBridge::v_leave()
+{
+ SAL_WARN_IF(m_count <= 0, "cppu.unsafebridge", "m_count is less than or equal to 0");
+
+ -- m_count;
+ if (!m_count)
+ m_threadId = 0;
+
+
+ m_mutex.release();
+}
+
+bool UnsafeBridge::v_isValid(OUString * pReason)
+{
+ bool result = m_count > 0;
+ if (!result)
+ {
+ *pReason = "not entered";
+ }
+ else
+ {
+ result = m_threadId == osl::Thread::getCurrentIdentifier();
+
+ if (!result)
+ *pReason = "wrong thread";
+ }
+
+ if (result)
+ *pReason = "OK";
+
+ return result;
+}
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv)
+ SAL_THROW_EXTERN_C()
+{
+ cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new UnsafeBridge());
+}
+
+extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo )
+{
+ cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/cppu/compat.cxx b/cppu/source/cppu/compat.cxx
new file mode 100644
index 000000000..06181e6ef
--- /dev/null
+++ b/cppu/source/cppu/compat.cxx
@@ -0,0 +1,47 @@
+/* -*- 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/.
+ */
+
+#include <sal/config.h>
+
+#include <cstdlib>
+
+#include <typelib/typedescription.h>
+#include <rtl/ustring.h>
+#include <sal/types.h>
+
+// Stubs for removed functionality, to be killed when we bump sal SONAME
+
+extern "C" {
+
+SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_static_array_type_init(
+ typelib_TypeDescriptionReference **, typelib_TypeDescriptionReference *,
+ sal_Int32, ...) SAL_THROW_EXTERN_C()
+{
+ std::abort();
+}
+
+SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_typedescription_newArray(
+ typelib_TypeDescription **, typelib_TypeDescriptionReference *,
+ sal_Int32, sal_Int32 *) SAL_THROW_EXTERN_C()
+{
+ std::abort();
+}
+
+SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_typedescription_newUnion(
+ typelib_TypeDescription **, rtl_uString *,
+ typelib_TypeDescriptionReference *, sal_Int64,
+ typelib_TypeDescriptionReference *, sal_Int32, void *)
+ SAL_THROW_EXTERN_C()
+{
+ std::abort();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/cppu/cppu_opt.cxx b/cppu/source/cppu/cppu_opt.cxx
new file mode 100644
index 000000000..40f90de6e
--- /dev/null
+++ b/cppu/source/cppu/cppu_opt.cxx
@@ -0,0 +1,66 @@
+/* -*- 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/uno/Any.hxx>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <rtl/ustring.hxx>
+
+
+using namespace ::rtl;
+
+
+extern "C" rtl_uString * SAL_CALL cppu_unsatisfied_iquery_msg(
+ typelib_TypeDescriptionReference * pType )
+ SAL_THROW_EXTERN_C()
+{
+ OUString ret = "unsatisfied query for interface of type "
+ + OUString::unacquired( &pType->pTypeName ) + "!";
+ rtl_uString_acquire( ret.pData );
+ return ret.pData;
+}
+
+
+extern "C" rtl_uString * SAL_CALL cppu_unsatisfied_iset_msg(
+ typelib_TypeDescriptionReference * pType )
+ SAL_THROW_EXTERN_C()
+{
+ OUString ret = "invalid attempt to assign an empty interface of type "
+ + OUString::unacquired( &pType->pTypeName ) + "!";
+ rtl_uString_acquire( ret.pData );
+ return ret.pData;
+}
+
+
+extern "C" rtl_uString * SAL_CALL cppu_Any_extraction_failure_msg(
+ uno_Any const * pAny, typelib_TypeDescriptionReference * pType )
+ SAL_THROW_EXTERN_C()
+{
+ OUString ret = "Cannot extract an Any(" +
+ OUString::unacquired(&pAny->pType->pTypeName) +
+ ") to " +
+ OUString::unacquired(&pType->pTypeName) +
+ "!";
+ rtl_uString_acquire( ret.pData );
+ return ret.pData;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/helper/purpenv/Proxy.hxx b/cppu/source/helper/purpenv/Proxy.hxx
new file mode 100644
index 000000000..02c65a23a
--- /dev/null
+++ b/cppu/source/helper/purpenv/Proxy.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <osl/interlck.h>
+
+#include <uno/environment.hxx>
+#include <uno/mapping.hxx>
+#include <uno/dispatcher.h>
+
+#include <cppu/helper/purpenv/Mapping.hxx>
+
+
+class Proxy : public uno_Interface
+{
+ oslInterlockedCount m_nRef;
+
+ css::uno::Environment m_from;
+ css::uno::Environment m_to;
+
+ css::uno::Mapping m_from_to;
+ css::uno::Mapping m_to_from;
+
+ // mapping information
+ uno_Interface * m_pUnoI; // wrapped interface
+ typelib_InterfaceTypeDescription * m_pTypeDescr;
+ OUString m_aOId;
+
+ cppu::helper::purpenv::ProbeFun * m_probeFun;
+ void * m_pProbeContext;
+
+public:
+ explicit Proxy(css::uno::Mapping to_from,
+ uno_Environment * pTo,
+ uno_Environment * pFrom,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId,
+ cppu::helper::purpenv::ProbeFun * probeFun,
+ void * pProbeContext);
+ ~Proxy();
+
+ void acquire();
+ void release();
+
+ void dispatch(
+ typelib_TypeDescriptionReference * pReturnTypeRef,
+ typelib_MethodParameter * pParams,
+ sal_Int32 nParams,
+ typelib_TypeDescription const * pMemberType,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException );
+
+};
+
+extern "C" void Proxy_free(uno_ExtEnvironment * pEnv, void * pProxy) SAL_THROW_EXTERN_C();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx b/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx
new file mode 100644
index 000000000..a0163939f
--- /dev/null
+++ b/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx
@@ -0,0 +1,522 @@
+/* -*- 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 <cppu/helper/purpenv/Environment.hxx>
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <uno/lbnames.h>
+#include <cppu/Enterable.hxx>
+
+#include <typelib/typedescription.h>
+#include <osl/interlck.h>
+#include <memory>
+
+extern "C" {
+typedef void EnvFun_P (uno_Environment *);
+typedef void EnvFun_PP_P(uno_Environment ** ppHardEnv, uno_Environment *);
+typedef void ExtEnv_registerProxyInterface (uno_ExtEnvironment *,
+ void ** ppProxy,
+ uno_freeProxyFunc freeProxy,
+ rtl_uString * pOId,
+ typelib_InterfaceTypeDescription * pTypeDescr);
+typedef void ExtEnv_revokeInterface (uno_ExtEnvironment *,
+ void * pInterface);
+typedef void ExtEnv_getObjectIdentifier (uno_ExtEnvironment *,
+ rtl_uString **,
+ void *);
+typedef void ExtEnv_getRegisteredInterface (uno_ExtEnvironment *,
+ void **,
+ rtl_uString *,
+ typelib_InterfaceTypeDescription *);
+typedef void ExtEnv_getRegisteredInterfaces(uno_ExtEnvironment *,
+ void *** pppInterfaces,
+ sal_Int32 * pnLen,
+ uno_memAlloc memAlloc);
+typedef void ExtEnv_computeObjectIdentifier(uno_ExtEnvironment *,
+ rtl_uString ** ppOId,
+ void * pInterface);
+typedef void ExtEnv_acquireInterface (uno_ExtEnvironment *,
+ void * pInterface);
+typedef void ExtEnv_releaseInterface (uno_ExtEnvironment *,
+ void * pInterface);
+}
+
+namespace {
+
+class Base : public cppu::Enterable
+{
+public:
+ explicit Base(uno_Environment * pEnv, cppu::Enterable * pEnterable);
+
+ void acquireWeak();
+ void releaseWeak();
+ void harden (uno_Environment ** ppHardEnv);
+ void acquire();
+ void release();
+
+ void registerProxyInterface (void ** ppProxy,
+ uno_freeProxyFunc freeProxy,
+ OUString const & oid,
+ typelib_InterfaceTypeDescription * pTypeDescr);
+ void revokeInterface (void * pInterface);
+ void getObjectIdentifier (void * pInterface,
+ OUString * pOid);
+ void getRegisteredInterface (void **,
+ OUString const & oid,
+ typelib_InterfaceTypeDescription *);
+ void getRegisteredInterfaces(void ***,
+ sal_Int32 * pnLen,
+ uno_memAlloc memAlloc);
+ void computeObjectIdentifier(void * pInterface,
+ OUString * pOid);
+ void acquireInterface (void * pInterface);
+ void releaseInterface (void * pInterface);
+
+ virtual void v_enter() override;
+ virtual void v_leave() override;
+ virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override;
+ virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override;
+ virtual bool v_isValid (OUString * pReason) override;
+
+protected:
+ oslInterlockedCount m_nRef;
+ uno_Environment * m_pEnv;
+ std::unique_ptr<cppu::Enterable> m_pEnterable;
+
+ EnvFun_P * m_env_acquire;
+ EnvFun_P * m_env_release;
+ EnvFun_PP_P * m_env_harden;
+ EnvFun_P * m_env_acquireWeak;
+ EnvFun_P * m_env_releaseWeak;
+
+ ExtEnv_registerProxyInterface * m_env_registerProxyInterface;
+ ExtEnv_revokeInterface * m_env_revokeInterface;
+ ExtEnv_getObjectIdentifier * m_env_getObjectIdentifier;
+ ExtEnv_getRegisteredInterface * m_env_getRegisteredInterface;
+ ExtEnv_getRegisteredInterfaces * m_env_getRegisteredInterfaces;
+ ExtEnv_computeObjectIdentifier * m_env_computeObjectIdentifier;
+ ExtEnv_acquireInterface * m_env_acquireInterface;
+ ExtEnv_releaseInterface * m_env_releaseInterface;
+
+ virtual ~Base() override;
+};
+
+}
+
+extern "C" {
+static void s_acquire(uno_Environment * pEnv) //SAL_THROW_EXTERN_C()
+{
+ Base * pBase = static_cast<Base *>(pEnv->pReserved);
+ pBase->acquire();
+}
+
+static void s_release(uno_Environment * pEnv) SAL_THROW_EXTERN_C()
+{
+ Base * pBase = static_cast<Base *>(pEnv->pReserved);
+ pBase->release();
+}
+
+static void s_harden(uno_Environment ** ppHardEnv, uno_Environment * pEnv) SAL_THROW_EXTERN_C()
+{
+ Base * pBase = static_cast<Base *>(pEnv->pReserved);
+ pBase->harden(ppHardEnv);
+}
+
+static void s_acquireWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C()
+{
+ Base * pBase = static_cast<Base *>(pEnv->pReserved);
+ pBase->acquireWeak();
+}
+
+static void s_releaseWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C()
+{
+ Base * pBase = static_cast<Base *>(pEnv->pReserved);
+ pBase->releaseWeak();
+}
+
+
+static void s_registerProxyInterface(uno_ExtEnvironment * pExtEnv,
+ void ** ppProxy,
+ uno_freeProxyFunc freeProxy,
+ rtl_uString * pOId,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->registerProxyInterface(ppProxy, freeProxy, pOId, pTypeDescr);
+}
+
+static void s_revokeInterface(uno_ExtEnvironment * pExtEnv, void * pInterface)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->revokeInterface(pInterface);
+}
+
+static void s_getObjectIdentifier(uno_ExtEnvironment * pExtEnv,
+ rtl_uString ** ppOId,
+ void * pInterface)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->getObjectIdentifier(pInterface, reinterpret_cast<OUString *>(ppOId));
+}
+
+static void s_getRegisteredInterface(uno_ExtEnvironment * pExtEnv,
+ void ** ppInterface,
+ rtl_uString * pOId,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->getRegisteredInterface(ppInterface, pOId, pTypeDescr);
+}
+
+static void s_getRegisteredInterfaces(uno_ExtEnvironment * pExtEnv,
+ void *** pppInterface,
+ sal_Int32 * pnLen,
+ uno_memAlloc memAlloc)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->getRegisteredInterfaces(pppInterface, pnLen, memAlloc);
+}
+
+static void s_computeObjectIdentifier(uno_ExtEnvironment * pExtEnv,
+ rtl_uString ** ppOId,
+ void * pInterface)
+{
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->computeObjectIdentifier(pInterface, reinterpret_cast<OUString *>(ppOId));
+}
+
+static void s_acquireInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) {
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->acquireInterface(pInterface);
+}
+
+static void s_releaseInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) {
+ Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved);
+ pBase->releaseInterface(pInterface);
+}
+
+}
+
+Base::Base(uno_Environment * pEnv, cppu::Enterable * pEnterable)
+ :m_nRef(1),
+ m_pEnv(pEnv),
+ m_pEnterable (pEnterable),
+ m_env_acquire (pEnv->acquire),
+ m_env_release (pEnv->release),
+ m_env_harden (pEnv->harden),
+ m_env_acquireWeak(pEnv->acquireWeak),
+ m_env_releaseWeak(pEnv->releaseWeak),
+ m_env_registerProxyInterface (pEnv->pExtEnv->registerProxyInterface),
+ m_env_revokeInterface (pEnv->pExtEnv->revokeInterface),
+ m_env_getObjectIdentifier (pEnv->pExtEnv->getObjectIdentifier),
+ m_env_getRegisteredInterface (pEnv->pExtEnv->getRegisteredInterface),
+ m_env_getRegisteredInterfaces(pEnv->pExtEnv->getRegisteredInterfaces),
+ m_env_computeObjectIdentifier(pEnv->pExtEnv->computeObjectIdentifier),
+ m_env_acquireInterface (pEnv->pExtEnv->acquireInterface),
+ m_env_releaseInterface (pEnv->pExtEnv->releaseInterface)
+{
+ SAL_INFO("cppu.purpenv", "LIFE: cppu::helper::purpenv::Base::Base(uno_Environment * pEnv) -> " << this);
+ OSL_ENSURE(
+ rtl_ustr_ascii_compare_WithLength(pEnv->pTypeName->buffer, rtl_str_getLength(UNO_LB_UNO), UNO_LB_UNO)
+ == 0,
+ "### wrong environment type!");
+
+ pEnv->acquire = s_acquire;
+ pEnv->release = s_release;
+ pEnv->harden = s_harden;
+ pEnv->acquireWeak = s_acquireWeak;
+ pEnv->releaseWeak = s_releaseWeak;
+
+ pEnv->pExtEnv->registerProxyInterface = s_registerProxyInterface;
+ pEnv->pExtEnv->revokeInterface = s_revokeInterface;
+ pEnv->pExtEnv->getObjectIdentifier = s_getObjectIdentifier;
+ pEnv->pExtEnv->getRegisteredInterface = s_getRegisteredInterface;
+ pEnv->pExtEnv->getRegisteredInterfaces = s_getRegisteredInterfaces;
+ pEnv->pExtEnv->computeObjectIdentifier = s_computeObjectIdentifier;
+ pEnv->pExtEnv->acquireInterface = s_acquireInterface;
+ pEnv->pExtEnv->releaseInterface = s_releaseInterface;
+
+ pEnv->pReserved = this;
+}
+
+Base::~Base()
+{
+ SAL_INFO("cppu.purpenv", "LIFE: cppu::helper::purpenv::Base::~Base() -> " << this);
+
+ m_pEnv->acquire = m_env_acquire;
+ m_pEnv->release = m_env_release;
+ m_pEnv->harden = m_env_harden;
+ m_pEnv->acquireWeak = m_env_acquireWeak;
+ m_pEnv->releaseWeak = m_env_releaseWeak;
+
+ m_pEnv->pReserved = nullptr;
+
+ m_pEnterable.reset();
+ m_pEnv->release(m_pEnv);
+}
+
+void Base::acquire()
+{
+ m_env_acquire(m_pEnv);
+
+ osl_atomic_increment(&m_nRef);
+}
+
+void Base::release()
+{
+ if (osl_atomic_decrement(&m_nRef) == 0)
+ delete this;
+
+ else
+ m_env_release(m_pEnv);
+}
+
+void Base::harden(uno_Environment ** ppHardEnv)
+{
+ m_env_harden(ppHardEnv, m_pEnv);
+ osl_atomic_increment(&m_nRef);
+}
+
+void Base::acquireWeak()
+{
+ m_env_acquireWeak(m_pEnv);
+}
+
+void Base::releaseWeak()
+{
+ m_env_releaseWeak(m_pEnv);
+}
+
+
+extern "C" { static void s_registerProxyInterface_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void ** ppProxy = va_arg(*pParam, void **);
+ uno_freeProxyFunc freeProxy = va_arg(*pParam, uno_freeProxyFunc);
+ rtl_uString * pOId = va_arg(*pParam, rtl_uString *);
+ typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
+ ExtEnv_registerProxyInterface * pRegisterProxyInterface
+ = va_arg(*pParam, ExtEnv_registerProxyInterface *);
+
+ pRegisterProxyInterface(pExtEnv, ppProxy, freeProxy, pOId, pTypeDescr);
+}}
+
+void Base::registerProxyInterface(void ** ppProxy,
+ uno_freeProxyFunc freeProxy,
+ OUString const & oid,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_registerProxyInterface_v,
+ m_pEnv->pExtEnv,
+ ppProxy,
+ freeProxy,
+ oid.pData,
+ pTypeDescr,
+ m_env_registerProxyInterface);
+}
+
+
+extern "C" { static void s_revokeInterface_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+ ExtEnv_revokeInterface * pRevokeInterface = va_arg(*pParam, ExtEnv_revokeInterface *);
+
+ pRevokeInterface(pExtEnv, pInterface);
+}}
+
+void Base::revokeInterface(void * pInterface)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_revokeInterface_v,
+ m_pEnv->pExtEnv,
+ pInterface,
+ m_env_revokeInterface);
+}
+
+
+extern "C" { static void s_getObjectIdentifier_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+ OUString * pOId = va_arg(*pParam, OUString *);
+ ExtEnv_getObjectIdentifier * pGetObjectIdentifier
+ = va_arg(*pParam, ExtEnv_getObjectIdentifier *);
+
+ pGetObjectIdentifier(pExtEnv, reinterpret_cast<rtl_uString **>(pOId), pInterface);
+}}
+
+void Base::getObjectIdentifier(void * pInterface, OUString * pOid)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_getObjectIdentifier_v,
+ m_pEnv->pExtEnv,
+ pInterface,
+ pOid,
+ m_env_getObjectIdentifier);
+}
+
+
+extern "C" { static void s_getRegisteredInterface_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void ** ppInterface = va_arg(*pParam, void **);
+ rtl_uString * pOId = va_arg(*pParam, rtl_uString *);
+ typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
+ ExtEnv_getRegisteredInterface * pGetRegisteredInterface
+ = va_arg(*pParam, ExtEnv_getRegisteredInterface *);
+
+ pGetRegisteredInterface(pExtEnv, ppInterface, pOId, pTypeDescr);
+}}
+
+void Base::getRegisteredInterface(void ** ppInterface,
+ OUString const & oid,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_getRegisteredInterface_v,
+ m_pEnv->pExtEnv,
+ ppInterface,
+ oid.pData,
+ pTypeDescr,
+ m_env_getRegisteredInterface);
+}
+
+
+extern "C" { static void s_getRegisteredInterfaces_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void *** pppInterface = va_arg(*pParam, void ***);
+ sal_Int32 * pnLen = va_arg(*pParam, sal_Int32 *);
+ uno_memAlloc memAlloc = va_arg(*pParam, uno_memAlloc);
+ ExtEnv_getRegisteredInterfaces * pGetRegisteredInterfaces
+ = va_arg(*pParam, ExtEnv_getRegisteredInterfaces *);
+
+ pGetRegisteredInterfaces(pExtEnv, pppInterface, pnLen, memAlloc);
+}}
+
+void Base::getRegisteredInterfaces(void *** pppInterface,
+ sal_Int32 * pnLen,
+ uno_memAlloc memAlloc)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_getRegisteredInterfaces_v,
+ m_pEnv->pExtEnv,
+ pppInterface,
+ pnLen,
+ memAlloc,
+ m_env_getRegisteredInterfaces);
+}
+
+
+extern "C" { static void s_computeObjectIdentifier_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+ OUString * pOId = va_arg(*pParam, OUString *);
+ ExtEnv_computeObjectIdentifier * pComputeObjectIdentifier
+ = va_arg(*pParam, ExtEnv_computeObjectIdentifier *);
+
+ pComputeObjectIdentifier(pExtEnv, reinterpret_cast<rtl_uString **>(pOId), pInterface);
+}}
+
+void Base::computeObjectIdentifier(void * pInterface, OUString * pOid)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_computeObjectIdentifier_v,
+ m_pEnv->pExtEnv,
+ pInterface,
+ pOid,
+ m_env_computeObjectIdentifier);
+}
+
+
+extern "C" { static void s_acquireInterface_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+ ExtEnv_acquireInterface * pAcquireInterface
+ = va_arg(*pParam, ExtEnv_acquireInterface *);
+
+ pAcquireInterface(pExtEnv, pInterface);
+}}
+
+void Base::acquireInterface(void * pInterface)
+{
+ uno_Environment_invoke(m_pEnv, s_acquireInterface_v, m_pEnv->pExtEnv, pInterface, m_env_acquireInterface);
+}
+
+
+extern "C" { static void s_releaseInterface_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+ ExtEnv_releaseInterface * pReleaseInterface
+ = va_arg(*pParam, ExtEnv_releaseInterface *);
+
+ pReleaseInterface(pExtEnv, pInterface);
+}}
+
+void Base::releaseInterface(void * pInterface)
+{
+ uno_Environment_invoke(m_pEnv,
+ s_releaseInterface_v,
+ m_pEnv->pExtEnv,
+ pInterface,
+ m_env_releaseInterface);
+}
+
+void Base::v_enter()
+{
+ m_pEnterable->enter();
+}
+
+void Base::v_leave()
+{
+ m_pEnterable->leave();
+}
+
+void Base::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ m_pEnterable->callInto_v(pCallee, pParam);
+}
+
+void Base::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam)
+{
+ m_pEnterable->callOut_v(pCallee, pParam);
+}
+
+bool Base::v_isValid(OUString * pReason)
+{
+ return m_pEnterable->isValid(pReason);
+}
+
+namespace cppu::helper::purpenv {
+
+void Environment_initWithEnterable(uno_Environment * pEnvironment, cppu::Enterable * pEnterable)
+{
+ new Base(pEnvironment, pEnterable);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx b/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx
new file mode 100644
index 000000000..f68a47390
--- /dev/null
+++ b/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx
@@ -0,0 +1,215 @@
+/* -*- 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 <cppu/helper/purpenv/Mapping.hxx>
+
+#include "Proxy.hxx"
+
+#include <osl/interlck.h>
+#include <sal/log.hxx>
+#include <uno/environment.hxx>
+#include <uno/dispatcher.h>
+
+using namespace com::sun::star;
+
+namespace {
+
+class Mapping : public uno_Mapping
+{
+ uno::Environment m_from;
+ uno::Environment m_to;
+
+ oslInterlockedCount m_nCount;
+
+ cppu::helper::purpenv::ProbeFun * m_probeFun;
+ void * m_pContext;
+
+public:
+ explicit Mapping(uno_Environment * pFrom,
+ uno_Environment * pTo,
+ cppu::helper::purpenv::ProbeFun * probeFun,
+ void * pProbeContext);
+ virtual ~Mapping();
+
+ void mapInterface(
+ uno_Interface ** ppOut,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr);
+
+ void acquire();
+ void release();
+};
+
+}
+
+static void s_mapInterface(
+ uno_Mapping * puno_Mapping,
+ void ** ppOut,
+ void * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr )
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
+ pMapping->mapInterface(
+ reinterpret_cast<uno_Interface **>(ppOut),
+ static_cast<uno_Interface *>(pUnoI), pTypeDescr);
+}
+
+extern "C" {
+static void s_acquire(uno_Mapping * puno_Mapping)
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
+ pMapping->acquire();
+}
+
+static void s_release(uno_Mapping * puno_Mapping)
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * pMapping = static_cast<Mapping * >(puno_Mapping);
+ pMapping->release();
+}
+
+
+static void s_getIdentifier_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ rtl_uString ** ppOid = va_arg(*pParam, rtl_uString **);
+ uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
+
+ pEnv->getObjectIdentifier(pEnv, ppOid, pUnoI);
+}
+
+static void s_free(uno_Mapping * puno_Mapping)
+ SAL_THROW_EXTERN_C()
+{
+ Mapping * pMapping = static_cast<Mapping *>(puno_Mapping);
+ delete pMapping;
+}
+}
+
+Mapping::Mapping(uno_Environment * pFrom,
+ uno_Environment * pTo,
+ cppu::helper::purpenv::ProbeFun * probeFun,
+ void * pProbeContext
+)
+ : m_from (pFrom),
+ m_to (pTo),
+ m_nCount (1),
+ m_probeFun(probeFun),
+ m_pContext(pProbeContext)
+{
+ SAL_INFO("cppu.purpenv", "LIFE: Mapping::Mapping(uno_Environment * pFrom, uno_Environment * pTo -> " << this);
+
+ uno_Mapping::acquire = s_acquire;
+ uno_Mapping::release = s_release;
+ uno_Mapping::mapInterface = s_mapInterface;
+}
+
+Mapping::~Mapping()
+{
+ SAL_INFO("cppu.purpenv", "LIFE: Mapping:~Mapping() -> " << this);
+}
+
+
+void Mapping::mapInterface(
+ uno_Interface ** ppOut,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr)
+{
+ OSL_ASSERT(ppOut && pTypeDescr);
+ if (*ppOut)
+ {
+ (*ppOut)->release(*ppOut);
+ *ppOut = nullptr;
+ }
+
+ if (!pUnoI)
+ return;
+
+ // get object id of uno interface to be wrapped
+ // need to enter environment because of potential "queryInterface" call
+ rtl_uString * pOId = nullptr;
+ uno_Environment_invoke(m_from.get(), s_getIdentifier_v, m_from.get(), &pOId, pUnoI);
+ OSL_ASSERT(pOId);
+
+ // try to get any known interface from target environment
+ m_to.get()->pExtEnv->getRegisteredInterface(m_to.get()->pExtEnv, reinterpret_cast<void **>(ppOut), pOId, pTypeDescr);
+
+ if (!*ppOut) // not yet there, register new proxy interface
+ {
+ // try to publish a new proxy (ref count initially 1)
+ uno_Interface * pProxy = new Proxy(this,
+ m_from.get(),
+ m_to.get(),
+ pUnoI,
+ pTypeDescr,
+ pOId,
+ m_probeFun,
+ m_pContext);
+
+ // proxy may be exchanged during registration
+ m_to.get()->pExtEnv->registerProxyInterface(m_to.get()->pExtEnv,
+ reinterpret_cast<void **>(&pProxy),
+ Proxy_free,
+ pOId,
+ pTypeDescr);
+
+ *ppOut = pProxy;
+ }
+
+ rtl_uString_release(pOId);
+}
+
+
+void Mapping::acquire()
+{
+ if (osl_atomic_increment(&m_nCount) == 1)
+ {
+ uno_Mapping * pMapping = this;
+
+ ::uno_registerMapping(&pMapping, s_free, m_from.get(), m_to.get(), nullptr);
+ }
+}
+
+void Mapping::release()
+{
+ if (osl_atomic_decrement(&m_nCount) == 0)
+ ::uno_revokeMapping(this);
+}
+
+
+namespace cppu::helper::purpenv {
+
+void createMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo,
+ ProbeFun * probeFun,
+ void * pContext
+ )
+{
+ *ppMapping = new Mapping(pFrom, pTo, probeFun, pContext);
+
+ ::uno_registerMapping(ppMapping, s_free, pFrom, pTo, nullptr);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx b/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx
new file mode 100644
index 000000000..db4820fc9
--- /dev/null
+++ b/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx
@@ -0,0 +1,504 @@
+/* -*- 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 "Proxy.hxx"
+
+#include <sal/log.hxx>
+#include <uno/dispatcher.h>
+#include <typelib/typedescription.hxx>
+#include <utility>
+
+using namespace com::sun::star;
+
+static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
+{
+ switch (pTypeDescr->eTypeClass)
+ {
+// case typelib_TypeClass_TYPEDEF:
+ case typelib_TypeClass_SEQUENCE:
+ {
+ switch (reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE:
+ case typelib_TypeClass_ANY: // might relate to interface
+ return true;
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType );
+ bool bRel = relatesToInterface( pTD );
+ TYPELIB_DANGER_RELEASE( pTD );
+ return bRel;
+ }
+ default:
+ ;
+ }
+ return false;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ // ...optimized... to avoid getDescription() calls!
+ typelib_CompoundTypeDescription * pComp = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr);
+ typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
+ for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
+ {
+ switch (pTypes[nPos]->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE:
+ case typelib_TypeClass_ANY: // might relate to interface
+ return true;
+// case typelib_TypeClass_TYPEDEF:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
+ bool bRel = relatesToInterface( pTD );
+ TYPELIB_DANGER_RELEASE( pTD );
+ if (bRel)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ if (pComp->pBaseTypeDescription)
+ return relatesToInterface( &pComp->pBaseTypeDescription->aBase );
+ break;
+ }
+ case typelib_TypeClass_ANY: // might relate to interface
+ case typelib_TypeClass_INTERFACE:
+ return true;
+
+ default:
+ ;
+ }
+ return false;
+}
+
+extern "C" { static void s_Proxy_dispatch(
+ uno_Interface * pUnoI,
+ typelib_TypeDescription const * pMemberType,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException)
+ SAL_THROW_EXTERN_C()
+{
+ Proxy * pThis = static_cast<Proxy *>(pUnoI);
+
+ typelib_MethodParameter param;
+ sal_Int32 nParams = 0;
+ typelib_MethodParameter * pParams = nullptr;
+ typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
+ // sal_Int32 nOutParams = 0;
+
+ switch (pMemberType->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ if (pReturn)
+ {
+ pReturnTypeRef =
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberType)->pAttributeTypeRef;
+ nParams = 0;
+ pParams = nullptr;
+ }
+ else
+ {
+ param.pTypeRef = reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberType)->pAttributeTypeRef;
+ param.bIn = true;
+ param.bOut = false;
+ nParams = 1;
+ pParams = &param;
+ }
+ break;
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const * method_td =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType);
+ pReturnTypeRef = method_td->pReturnTypeRef;
+ nParams = method_td->nParams;
+ pParams = method_td->pParams;
+ break;
+ }
+ default:
+ OSL_FAIL( "### illegal member typeclass!" );
+ abort();
+ }
+
+ pThis->dispatch( pReturnTypeRef,
+ pParams,
+ nParams,
+ pMemberType,
+ pReturn,
+ pArgs,
+ ppException );
+}}
+
+extern "C" void Proxy_free(SAL_UNUSED_PARAMETER uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
+{
+ Proxy * pThis = static_cast<Proxy * >(static_cast<uno_Interface *>(pProxy));
+ delete pThis;
+}
+
+extern "C" {
+static void s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
+{
+ Proxy * pProxy = static_cast<Proxy *>(pUnoI);
+ pProxy->acquire();
+}
+
+static void s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
+{
+ Proxy * pProxy = static_cast<Proxy *>(pUnoI);
+ pProxy->release();
+}
+
+static void s_acquireAndRegister_v(va_list * pParam)
+{
+ uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
+ rtl_uString * pOid = va_arg(*pParam, rtl_uString *);
+ typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+
+ pUnoI->acquire(pUnoI);
+ pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
+}
+}
+
+Proxy::Proxy(uno::Mapping to_from,
+ uno_Environment * pTo,
+ uno_Environment * pFrom,
+ uno_Interface * pUnoI,
+ typelib_InterfaceTypeDescription * pTypeDescr,
+ OUString const & rOId,
+ cppu::helper::purpenv::ProbeFun * probeFun,
+ void * pProbeContext
+)
+ : m_nRef (1),
+ m_from (pFrom),
+ m_to (pTo),
+ m_from_to (pFrom, pTo),
+ m_to_from (std::move(to_from)),
+ m_pUnoI (pUnoI),
+ m_pTypeDescr (pTypeDescr),
+ m_aOId (rOId),
+ m_probeFun (probeFun),
+ m_pProbeContext(pProbeContext)
+{
+ SAL_INFO("cppu.purpenv", "LIFE: Proxy::Proxy(<>) -> " << this);
+
+ typelib_typedescription_acquire(&m_pTypeDescr->aBase);
+ if (!m_pTypeDescr->aBase.bComplete)
+ typelib_typedescription_complete(reinterpret_cast<typelib_TypeDescription **>(&m_pTypeDescr));
+
+ OSL_ENSURE(m_pTypeDescr->aBase.bComplete, "### type is incomplete!");
+
+ uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
+
+ // uno_Interface
+ uno_Interface::acquire = s_Proxy_acquire;
+ uno_Interface::release = s_Proxy_release;
+ uno_Interface::pDispatcher = s_Proxy_dispatch;
+}
+
+extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
+{
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
+
+ pEnv->revokeInterface(pEnv, pUnoI);
+ pUnoI->release(pUnoI);
+}}
+
+Proxy::~Proxy()
+{
+ SAL_INFO("cppu.purpenv", "LIFE: Proxy::~Proxy() -> " << this);
+
+ uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
+
+ typelib_typedescription_release(&m_pTypeDescr->aBase);
+}
+
+static uno::TypeDescription getAcquireMethod()
+{
+ typelib_TypeDescriptionReference * type_XInterface =
+ * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
+
+ typelib_TypeDescription * pTXInterfaceDescr = nullptr;
+ TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
+ uno::TypeDescription acquire(
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ pTXInterfaceDescr)->ppAllMembers[1]);
+ TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
+
+ return acquire;
+}
+
+static uno::TypeDescription getReleaseMethod()
+{
+ typelib_TypeDescriptionReference * type_XInterface =
+ * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
+
+ typelib_TypeDescription * pTXInterfaceDescr = nullptr;
+ TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
+ uno::TypeDescription release(
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ pTXInterfaceDescr)->ppAllMembers[2]);
+ TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
+
+ return release;
+}
+
+static uno::TypeDescription s_acquireMethod(getAcquireMethod());
+static uno::TypeDescription s_releaseMethod(getReleaseMethod());
+
+void Proxy::acquire()
+{
+ if (m_probeFun)
+ m_probeFun(true,
+ this,
+ m_pProbeContext,
+ *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
+ nullptr,
+ 0,
+ s_acquireMethod.get(),
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (osl_atomic_increment(&m_nRef) == 1)
+ {
+ // rebirth of proxy zombie
+ void * pThis = this;
+ m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
+ &pThis,
+ Proxy_free,
+ m_aOId.pData,
+ m_pTypeDescr);
+ OSL_ASSERT(pThis == this);
+ }
+
+ if (m_probeFun)
+ m_probeFun(false,
+ this,
+ m_pProbeContext,
+ *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
+ nullptr,
+ 0,
+ s_acquireMethod.get(),
+ nullptr,
+ nullptr,
+ nullptr);
+
+}
+
+void Proxy::release()
+{
+ cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
+ void * pProbeContext = m_pProbeContext;
+
+ if (m_probeFun)
+ m_probeFun(true,
+ this,
+ m_pProbeContext,
+ *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
+ nullptr,
+ 0,
+ s_releaseMethod.get(),
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (osl_atomic_decrement(&m_nRef) == 0)
+ m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
+
+ if (probeFun)
+ probeFun(false,
+ this,
+ pProbeContext,
+ *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
+ nullptr,
+ 0,
+ s_releaseMethod.get(),
+ nullptr,
+ nullptr,
+ nullptr);
+
+}
+
+
+extern "C" {
+static void s_type_destructData_v(va_list * pParam)
+{
+ void * ret = va_arg(*pParam, void *);
+ typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
+
+ uno_type_destructData(ret, pReturnTypeRef, nullptr);
+}
+
+static void s_dispatcher_v(va_list * pParam)
+{
+ uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
+ typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
+ void * pReturn = va_arg(*pParam, void *);
+ void ** pArgs = va_arg(*pParam, void **);
+ uno_Any ** ppException = va_arg(*pParam, uno_Any **);
+
+ pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
+}
+}
+
+void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
+ typelib_MethodParameter * pParams,
+ sal_Int32 nParams,
+ typelib_TypeDescription const * pMemberType,
+ void * pReturn,
+ void * pArgs[],
+ uno_Any ** ppException)
+{
+ if (m_probeFun)
+ m_probeFun(true,
+ this,
+ m_pProbeContext,
+ pReturnTypeRef,
+ pParams,
+ nParams,
+ pMemberType,
+ pReturn,
+ pArgs,
+ ppException);
+
+ void ** args = static_cast<void **>(alloca( sizeof (void *) * nParams ));
+
+ typelib_TypeDescription * return_td = nullptr;
+ void * ret = pReturn;
+ if (pReturnTypeRef)
+ {
+ TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
+
+ if (relatesToInterface(return_td))
+ ret = alloca(return_td->nSize);
+
+ TYPELIB_DANGER_RELEASE(return_td);
+ }
+
+ for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
+ {
+ typelib_MethodParameter const & param = pParams[nPos];
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET( &td, param.pTypeRef );
+ if (relatesToInterface(td))
+ {
+ args[nPos] = alloca(td->nSize);
+ if (param.bIn)
+ {
+ uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
+ }
+ }
+ else
+ {
+ args[nPos] = pArgs[nPos];
+ }
+ TYPELIB_DANGER_RELEASE( td );
+ }
+
+ uno_Any exc_data;
+ uno_Any * exc = &exc_data;
+
+ // do the UNO call...
+ uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
+
+ if (exc == nullptr)
+ {
+ for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
+ {
+ if (args[nPos] != pArgs[nPos])
+ {
+ typelib_MethodParameter const & param = pParams[nPos];
+ if (param.bOut)
+ {
+ if (param.bIn) // is inout
+ {
+ uno_type_destructData(pArgs[nPos], param.pTypeRef, nullptr);
+ }
+ uno_type_copyAndConvertData(pArgs[ nPos ],
+ args[ nPos ],
+ param.pTypeRef,
+ m_to_from.get());
+ }
+ uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
+ }
+ }
+ if (ret != pReturn)
+ {
+ uno_type_copyAndConvertData(pReturn,
+ ret,
+ pReturnTypeRef,
+ m_to_from.get());
+
+ uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
+ }
+
+ *ppException = nullptr;
+ }
+ else // exception occurred
+ {
+ for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
+ {
+ if (args[nPos] != pArgs[nPos])
+ {
+ typelib_MethodParameter const & param = pParams[nPos];
+ if (param.bIn)
+ {
+ uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
+ }
+ }
+ }
+
+ uno_type_any_constructAndConvert(*ppException,
+ exc->pData,
+ exc->pType,
+ m_to_from.get());
+
+ // FIXME: need to destruct in m_to
+ uno_any_destruct(exc, nullptr);
+ }
+
+ if (m_probeFun)
+ m_probeFun(false,
+ this,
+ m_pProbeContext,
+ pReturnTypeRef,
+ pParams,
+ nParams,
+ pMemberType,
+ pReturn,
+ pArgs,
+ ppException);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/current.cxx b/cppu/source/threadpool/current.cxx
new file mode 100644
index 000000000..64e6bfb8f
--- /dev/null
+++ b/cppu/source/threadpool/current.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 <sal/config.h>
+
+#include <rtl/byteseq.h>
+#include <osl/mutex.hxx>
+
+#include <uno/current_context.h>
+#include <uno/environment.hxx>
+#include <uno/mapping.hxx>
+#include <typelib/typedescription.h>
+
+#include "current.hxx"
+
+
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::cppu;
+using namespace ::com::sun::star::uno;
+
+namespace cppu
+{
+
+static typelib_InterfaceTypeDescription * get_type_XCurrentContext()
+{
+ static typelib_InterfaceTypeDescription* s_type_XCurrentContext = []() {
+ OUString sTypeName("com.sun.star.uno.XCurrentContext");
+ typelib_InterfaceTypeDescription* pTD = nullptr;
+ typelib_TypeDescriptionReference* pMembers[1] = { nullptr };
+ OUString sMethodName0("com.sun.star.uno.XCurrentContext::getValueByName");
+ typelib_typedescriptionreference_new(&pMembers[0], typelib_TypeClass_INTERFACE_METHOD,
+ sMethodName0.pData);
+ typelib_typedescription_newInterface(
+ &pTD, sTypeName.pData, 0, 0, 0, 0, 0,
+ *typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE), 1, pMembers);
+
+ typelib_typedescription_register(reinterpret_cast<typelib_TypeDescription**>(&pTD));
+ typelib_typedescriptionreference_release(pMembers[0]);
+
+ typelib_InterfaceMethodTypeDescription* pMethod = nullptr;
+ typelib_Parameter_Init aParameters[1];
+ OUString sParamName0("Name");
+ OUString sParamType0("string");
+ aParameters[0].pParamName = sParamName0.pData;
+ aParameters[0].eTypeClass = typelib_TypeClass_STRING;
+ aParameters[0].pTypeName = sParamType0.pData;
+ aParameters[0].bIn = true;
+ aParameters[0].bOut = false;
+ rtl_uString* pExceptions[1];
+ OUString sExceptionName0("com.sun.star.uno.RuntimeException");
+ pExceptions[0] = sExceptionName0.pData;
+ OUString sReturnType0("any");
+ typelib_typedescription_newInterfaceMethod(&pMethod, 3, false, sMethodName0.pData,
+ typelib_TypeClass_ANY, sReturnType0.pData, 1,
+ aParameters, 1, pExceptions);
+ typelib_typedescription_register(reinterpret_cast<typelib_TypeDescription**>(&pMethod));
+ typelib_typedescription_release(&pMethod->aBase.aBase);
+ // another static ref:
+ ++reinterpret_cast<typelib_TypeDescription*>(pTD)->nStaticRefCount;
+ return pTD;
+ }();
+
+ return s_type_XCurrentContext;
+}
+
+IdContainer::IdContainer()
+ : pCurrentContext(nullptr)
+ , pCurrentContextEnv(nullptr)
+ , pLocalThreadId(nullptr)
+ , pCurrentId(nullptr)
+ , nRefCountOfCurrentId(0)
+ , bInit(false)
+{
+}
+
+IdContainer::~IdContainer()
+{
+ if (pCurrentContext)
+ {
+ (*pCurrentContextEnv->releaseInterface)(
+ pCurrentContextEnv, pCurrentContext );
+ (*pCurrentContextEnv->aBase.release)(
+ &pCurrentContextEnv->aBase );
+ }
+ if (bInit)
+ {
+ ::rtl_byte_sequence_release( pLocalThreadId );
+ ::rtl_byte_sequence_release( pCurrentId );
+ }
+}
+
+IdContainer& getIdContainer()
+{
+ static thread_local IdContainer aId;
+ return aId;
+}
+
+}
+
+extern "C" sal_Bool SAL_CALL uno_setCurrentContext(
+ void * pCurrentContext,
+ rtl_uString * pEnvTypeName, void * pEnvContext )
+ SAL_THROW_EXTERN_C()
+{
+ IdContainer& id = getIdContainer();
+
+ // free old one
+ if (id.pCurrentContext)
+ {
+ (*id.pCurrentContextEnv->releaseInterface)(
+ id.pCurrentContextEnv, id.pCurrentContext );
+ (*id.pCurrentContextEnv->aBase.release)(
+ &id.pCurrentContextEnv->aBase );
+ id.pCurrentContextEnv = nullptr;
+
+ id.pCurrentContext = nullptr;
+ }
+
+ if (!pCurrentContext)
+ return true;
+
+ uno_Environment * pEnv = nullptr;
+ ::uno_getEnvironment( &pEnv, pEnvTypeName, pEnvContext );
+ OSL_ASSERT( pEnv && pEnv->pExtEnv );
+ if (pEnv)
+ {
+ if (pEnv->pExtEnv)
+ {
+ id.pCurrentContextEnv = pEnv->pExtEnv;
+ (*id.pCurrentContextEnv->acquireInterface)(
+ id.pCurrentContextEnv, pCurrentContext );
+ id.pCurrentContext = pCurrentContext;
+ }
+ else
+ {
+ (*pEnv->release)( pEnv );
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+}
+
+extern "C" sal_Bool SAL_CALL uno_getCurrentContext(
+ void ** ppCurrentContext, rtl_uString * pEnvTypeName, void * pEnvContext )
+ SAL_THROW_EXTERN_C()
+{
+ IdContainer& id = getIdContainer();
+
+ Environment target_env;
+
+ // release inout parameter
+ if (*ppCurrentContext)
+ {
+ target_env = Environment(OUString(pEnvTypeName), pEnvContext);
+ OSL_ASSERT( target_env.is() );
+ if (! target_env.is())
+ return false;
+ uno_ExtEnvironment * pEnv = target_env.get()->pExtEnv;
+ OSL_ASSERT( nullptr != pEnv );
+ if (nullptr == pEnv)
+ return false;
+ (*pEnv->releaseInterface)( pEnv, *ppCurrentContext );
+
+ *ppCurrentContext = nullptr;
+ }
+
+ // case: null-ref
+ if (nullptr == id.pCurrentContext)
+ return true;
+
+ if (! target_env.is())
+ {
+ target_env = Environment(OUString(pEnvTypeName), pEnvContext);
+ OSL_ASSERT( target_env.is() );
+ if (! target_env.is())
+ return false;
+ }
+
+ Mapping mapping(&id.pCurrentContextEnv->aBase, target_env.get());
+ OSL_ASSERT( mapping.is() );
+ if (! mapping.is())
+ return false;
+
+ mapping.mapInterface(ppCurrentContext, id.pCurrentContext, ::cppu::get_type_XCurrentContext());
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/current.hxx b/cppu/source/threadpool/current.hxx
new file mode 100644
index 000000000..1f6ce6642
--- /dev/null
+++ b/cppu/source/threadpool/current.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+struct _uno_ExtEnvironment;
+
+namespace cppu
+{
+struct IdContainer
+{
+ void * pCurrentContext;
+ _uno_ExtEnvironment * pCurrentContextEnv;
+
+ sal_Sequence * pLocalThreadId;
+ sal_Sequence * pCurrentId;
+ sal_Int32 nRefCountOfCurrentId;
+ bool bInit;
+
+ IdContainer();
+ ~IdContainer();
+};
+
+IdContainer& getIdContainer();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/jobqueue.cxx b/cppu/source/threadpool/jobqueue.cxx
new file mode 100644
index 000000000..1be424024
--- /dev/null
+++ b/cppu/source/threadpool/jobqueue.cxx
@@ -0,0 +1,177 @@
+/* -*- 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 "jobqueue.hxx"
+#include "threadpool.hxx"
+
+namespace cppu_threadpool {
+
+ JobQueue::JobQueue() :
+ m_nToDo( 0 ),
+ m_bSuspended( false ),
+ m_DisposedCallerAdmin( DisposedCallerAdmin::getInstance() )
+ {
+ }
+
+ void JobQueue::add( void *pThreadSpecificData, RequestFun * doRequest )
+ {
+ std::scoped_lock guard( m_mutex );
+ Job job = { pThreadSpecificData , doRequest };
+ m_lstJob.push_back( job );
+ if( ! m_bSuspended )
+ {
+ m_cndWait.notify_all();
+ }
+ m_nToDo ++;
+ }
+
+ void *JobQueue::enter( void const * nDisposeId , bool bReturnWhenNoJob )
+ {
+ void *pReturn = nullptr;
+ {
+ // synchronize with the dispose calls
+ std::scoped_lock guard( m_mutex );
+ if( m_DisposedCallerAdmin->isDisposed( nDisposeId ) )
+ {
+ return nullptr;
+ }
+ m_lstCallstack.push_front( nDisposeId );
+ }
+
+
+ while( true )
+ {
+ struct Job job={nullptr,nullptr};
+ {
+ std::unique_lock guard( m_mutex );
+
+ while (m_bSuspended
+ || (m_lstCallstack.front() != nullptr && !bReturnWhenNoJob
+ && m_lstJob.empty()))
+ {
+ m_cndWait.wait(guard);
+ }
+
+ if( nullptr == m_lstCallstack.front() )
+ {
+ // disposed !
+ if (!m_lstJob.empty() && m_lstJob.front().doRequest == nullptr) {
+ // If this thread was waiting for a remote response, that response may or
+ // may not have been enqueued; if it has not been enqueued, there cannot be
+ // another enqueued response, so it is always correct to remove any enqueued
+ // response here:
+ m_lstJob.pop_front();
+ }
+ break;
+ }
+
+ if( m_lstJob.empty() )
+ {
+ assert(bReturnWhenNoJob);
+ break;
+ }
+
+ job = m_lstJob.front();
+ m_lstJob.pop_front();
+ }
+
+ if( job.doRequest )
+ {
+ job.doRequest( job.pThreadSpecificData );
+ std::scoped_lock guard( m_mutex );
+ m_nToDo --;
+ }
+ else
+ {
+ pReturn = job.pThreadSpecificData;
+ std::scoped_lock guard( m_mutex );
+ m_nToDo --;
+ break;
+ }
+ }
+
+ {
+ // synchronize with the dispose calls
+ std::scoped_lock guard( m_mutex );
+ m_lstCallstack.pop_front();
+ }
+
+ return pReturn;
+ }
+
+ void JobQueue::dispose( void const * nDisposeId )
+ {
+ std::scoped_lock guard( m_mutex );
+ for( auto& rId : m_lstCallstack )
+ {
+ if( rId == nDisposeId )
+ {
+ rId = nullptr;
+ }
+ }
+
+ if( !m_lstCallstack.empty() && ! m_lstCallstack.front() )
+ {
+ // The thread is waiting for a disposed pCallerId, let it go
+ m_cndWait.notify_all();
+ }
+ }
+
+ void JobQueue::suspend()
+ {
+ std::scoped_lock guard( m_mutex );
+ m_bSuspended = true;
+ }
+
+ void JobQueue::resume()
+ {
+ std::scoped_lock guard( m_mutex );
+ m_bSuspended = false;
+ if( ! m_lstJob.empty() )
+ {
+ m_cndWait.notify_all();
+ }
+ }
+
+ bool JobQueue::isEmpty() const
+ {
+ std::scoped_lock guard( m_mutex );
+ return m_lstJob.empty();
+ }
+
+ bool JobQueue::isCallstackEmpty() const
+ {
+ std::scoped_lock guard( m_mutex );
+ return m_lstCallstack.empty();
+ }
+
+ bool JobQueue::isBusy() const
+ {
+ std::scoped_lock guard( m_mutex );
+ return m_nToDo > 0;
+ }
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/jobqueue.hxx b/cppu/source/threadpool/jobqueue.hxx
new file mode 100644
index 000000000..5b92f2476
--- /dev/null
+++ b/cppu/source/threadpool/jobqueue.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <condition_variable>
+#include <deque>
+#include <memory>
+#include <mutex>
+
+#include <sal/types.h>
+
+namespace cppu_threadpool
+{
+ extern "C" typedef void (RequestFun)(void *);
+
+ struct Job
+ {
+ void *pThreadSpecificData;
+ RequestFun * doRequest;
+ };
+
+ class DisposedCallerAdmin;
+ typedef std::shared_ptr<DisposedCallerAdmin> DisposedCallerAdminHolder;
+
+ class JobQueue
+ {
+ public:
+ JobQueue();
+
+ void add( void *pThreadSpecificData, RequestFun * doRequest );
+
+ void *enter( void const * nDisposeId , bool bReturnWhenNoJob = false );
+ void dispose( void const * nDisposeId );
+
+ void suspend();
+ void resume();
+
+ bool isEmpty() const;
+ bool isCallstackEmpty() const;
+ bool isBusy() const;
+
+ private:
+ mutable std::mutex m_mutex;
+ std::deque < struct Job > m_lstJob;
+ std::deque<void const *> m_lstCallstack;
+ sal_Int32 m_nToDo;
+ bool m_bSuspended;
+ std::condition_variable m_cndWait;
+ DisposedCallerAdminHolder m_DisposedCallerAdmin;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/thread.cxx b/cppu/source/threadpool/thread.cxx
new file mode 100644
index 000000000..56e52838b
--- /dev/null
+++ b/cppu/source/threadpool/thread.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 <algorithm>
+#include <cstdlib>
+#include <osl/diagnose.h>
+#include <uno/threadpool.h>
+#include <sal/log.hxx>
+#include <utility>
+
+#include "thread.hxx"
+#include "jobqueue.hxx"
+#include "threadpool.hxx"
+
+using namespace osl;
+using namespace rtl;
+
+namespace cppu_threadpool {
+
+
+ ThreadAdmin::ThreadAdmin(): m_disposed(false) {}
+
+ ThreadAdmin::~ThreadAdmin()
+ {
+ SAL_WARN_IF(m_deque.size(), "cppu.threadpool", m_deque.size() << "Threads left");
+ }
+
+ bool ThreadAdmin::add_locked( rtl::Reference< ORequestThread > const & p )
+ {
+ if( m_disposed )
+ {
+ return false;
+ }
+ m_deque.push_back( p );
+ return true;
+ }
+
+ void ThreadAdmin::remove_locked( rtl::Reference< ORequestThread > const & p )
+ {
+ m_deque.erase(std::find( m_deque.begin(), m_deque.end(), p ), m_deque.end());
+ }
+
+ void ThreadAdmin::remove( rtl::Reference< ORequestThread > const & p )
+ {
+ std::scoped_lock aGuard( m_mutex );
+ remove_locked( p );
+ }
+
+ void ThreadAdmin::join()
+ {
+ {
+ std::scoped_lock aGuard( m_mutex );
+ m_disposed = true;
+ }
+ for (;;)
+ {
+ rtl::Reference< ORequestThread > pCurrent;
+ {
+ std::scoped_lock aGuard( m_mutex );
+ if( m_deque.empty() )
+ {
+ break;
+ }
+ pCurrent = m_deque.front();
+ m_deque.pop_front();
+ }
+ if (pCurrent->getIdentifier()
+ != osl::Thread::getCurrentIdentifier())
+ {
+ pCurrent->join();
+ }
+ }
+ }
+
+
+ ORequestThread::ORequestThread( ThreadPoolHolder aThreadPool,
+ JobQueue *pQueue,
+ ByteSequence aThreadId,
+ bool bAsynchron )
+ : m_aThreadPool(std::move( aThreadPool ))
+ , m_pQueue( pQueue )
+ , m_aThreadId(std::move( aThreadId ))
+ , m_bAsynchron( bAsynchron )
+ {}
+
+ ORequestThread::~ORequestThread() {}
+
+ void ORequestThread::setTask( JobQueue *pQueue,
+ const ByteSequence &aThreadId,
+ bool bAsynchron )
+ {
+ m_pQueue = pQueue;
+ m_aThreadId = aThreadId;
+ m_bAsynchron = bAsynchron;
+ }
+
+ bool ORequestThread::launch()
+ {
+ // Assumption is that osl::Thread::create returns normally with a true
+ // return value iff it causes osl::Thread::run to start executing:
+ acquire();
+ ThreadAdmin & rThreadAdmin = m_aThreadPool->getThreadAdmin();
+ std::unique_lock g(rThreadAdmin.m_mutex);
+ if (!rThreadAdmin.add_locked( this )) {
+ return false;
+ }
+ try {
+ if (!create()) {
+ std::abort();
+ }
+ } catch (...) {
+ rThreadAdmin.remove_locked( this );
+ g.release();
+ release();
+ throw;
+ }
+ return true;
+ }
+
+ void ORequestThread::onTerminated()
+ {
+ m_aThreadPool->getThreadAdmin().remove( this );
+ release();
+ }
+
+ void ORequestThread::run()
+ {
+ osl_setThreadName("cppu_threadpool::ORequestThread");
+
+ try
+ {
+ while ( m_pQueue )
+ {
+ if( ! m_bAsynchron )
+ {
+ if ( !uno_bindIdToCurrentThread( m_aThreadId.getHandle() ) )
+ {
+ OSL_ASSERT( false );
+ }
+ }
+
+ while( ! m_pQueue->isEmpty() )
+ {
+ // Note : Oneways should not get a disposable disposeid,
+ // It does not make sense to dispose a call in this state.
+ // That's way we put it a disposeid, that can't be used otherwise.
+ m_pQueue->enter(
+ this,
+ true );
+
+ if( m_pQueue->isEmpty() )
+ {
+ m_aThreadPool->revokeQueue( m_aThreadId , m_bAsynchron );
+ // Note : revokeQueue might have failed because m_pQueue.isEmpty()
+ // may be false (race).
+ }
+ }
+
+ delete m_pQueue;
+ m_pQueue = nullptr;
+
+ if( ! m_bAsynchron )
+ {
+ uno_releaseIdFromCurrentThread();
+ }
+
+ m_aThreadPool->waitInPool( this );
+ }
+ }
+ catch (...)
+ {
+ // Work around the problem that onTerminated is not called if run
+ // throws an exception:
+ onTerminated();
+ throw;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/thread.hxx b/cppu/source/threadpool/thread.hxx
new file mode 100644
index 000000000..5d03de88e
--- /dev/null
+++ b/cppu/source/threadpool/thread.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 .
+ */
+#pragma once
+
+#include <osl/thread.hxx>
+#include <sal/types.h>
+#include <salhelper/simplereferenceobject.hxx>
+
+#include "threadpool.hxx"
+
+namespace cppu_threadpool {
+
+ class JobQueue;
+
+
+ // private thread class for the threadpool
+
+ class ORequestThread:
+ public salhelper::SimpleReferenceObject, public osl::Thread
+ {
+ public:
+ ORequestThread( ThreadPoolHolder aThreadPool,
+ JobQueue * ,
+ ::rtl::ByteSequence aThreadId,
+ bool bAsynchron );
+ virtual ~ORequestThread() override;
+
+ void setTask( JobQueue * , const ::rtl::ByteSequence & aThreadId , bool bAsynchron );
+
+ bool launch();
+
+ static void * operator new(std::size_t size)
+ { return SimpleReferenceObject::operator new(size); }
+
+ static void operator delete(void * pointer)
+ { SimpleReferenceObject::operator delete(pointer); }
+
+ private:
+ virtual void SAL_CALL run() override;
+ virtual void SAL_CALL onTerminated() override;
+
+ ThreadPoolHolder m_aThreadPool;
+ JobQueue *m_pQueue;
+ ::rtl::ByteSequence m_aThreadId;
+ bool m_bAsynchron;
+ };
+
+} // end cppu_threadpool
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/threadident.cxx b/cppu/source/threadpool/threadident.cxx
new file mode 100644
index 000000000..16b7c0b27
--- /dev/null
+++ b/cppu/source/threadpool/threadident.cxx
@@ -0,0 +1,120 @@
+/* -*- 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/thread.hxx>
+#include <osl/diagnose.h>
+
+#include <rtl/process.h>
+#include <rtl/byteseq.hxx>
+
+#include <uno/threadpool.h>
+
+#include "current.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::cppu;
+
+static void createLocalId( sal_Sequence **ppThreadId )
+{
+ rtl_byte_sequence_constructNoDefault( ppThreadId , 4 + 16 );
+ sal_uInt32 id = osl::Thread::getCurrentIdentifier();
+ (*ppThreadId)->elements[0] = id & 0xFF;
+ (*ppThreadId)->elements[1] = (id >> 8) & 0xFF;
+ (*ppThreadId)->elements[2] = (id >> 16) & 0xFF;
+ (*ppThreadId)->elements[3] = (id >> 24) & 0xFF;
+ rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8 *>(&(*ppThreadId)->elements[4]) );
+}
+
+extern "C" void SAL_CALL
+uno_getIdOfCurrentThread( sal_Sequence **ppThreadId )
+ SAL_THROW_EXTERN_C()
+{
+ IdContainer& id = getIdContainer();
+ if (!id.bInit)
+ {
+ // first time, that the thread enters the bridge
+ createLocalId( ppThreadId );
+
+ // TODO
+ // note : this is a leak !
+ id.pLocalThreadId = *ppThreadId;
+ id.pCurrentId = *ppThreadId;
+ id.nRefCountOfCurrentId = 1;
+ rtl_byte_sequence_acquire( id.pLocalThreadId );
+ rtl_byte_sequence_acquire( id.pCurrentId );
+ id.bInit = true;
+ }
+ else
+ {
+ id.nRefCountOfCurrentId ++;
+ if( *ppThreadId )
+ {
+ rtl_byte_sequence_release( *ppThreadId );
+ }
+ *ppThreadId = id.pCurrentId;
+ rtl_byte_sequence_acquire( *ppThreadId );
+ }
+}
+
+extern "C" void SAL_CALL uno_releaseIdFromCurrentThread()
+ SAL_THROW_EXTERN_C()
+{
+ IdContainer& id = getIdContainer();
+ OSL_ASSERT( id.bInit );
+ OSL_ASSERT( id.nRefCountOfCurrentId );
+
+ id.nRefCountOfCurrentId --;
+ if( ! id.nRefCountOfCurrentId && (id.pLocalThreadId != id.pCurrentId) )
+ {
+ rtl_byte_sequence_assign( &(id.pCurrentId) , id.pLocalThreadId );
+ }
+}
+
+extern "C" sal_Bool SAL_CALL uno_bindIdToCurrentThread( sal_Sequence *pThreadId )
+ SAL_THROW_EXTERN_C()
+{
+ IdContainer& id = getIdContainer();
+ if (!id.bInit)
+ {
+ id.pLocalThreadId = nullptr;
+ createLocalId( &(id.pLocalThreadId) );
+ id.nRefCountOfCurrentId = 1;
+ id.pCurrentId = pThreadId;
+ rtl_byte_sequence_acquire(id.pCurrentId);
+ id.bInit = true;
+ }
+ else
+ {
+ OSL_ASSERT( 0 == id.nRefCountOfCurrentId );
+ if( 0 == id.nRefCountOfCurrentId )
+ {
+ rtl_byte_sequence_assign(&( id.pCurrentId ), pThreadId );
+ id.nRefCountOfCurrentId ++;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/threadpool.cxx b/cppu/source/threadpool/threadpool.cxx
new file mode 100644
index 000000000..897bebed9
--- /dev/null
+++ b/cppu/source/threadpool/threadpool.cxx
@@ -0,0 +1,476 @@
+/* -*- 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 <chrono>
+#include <algorithm>
+#include <utility>
+#include <unordered_map>
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <uno/threadpool.h>
+
+#include "threadpool.hxx"
+#include "thread.hxx"
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::rtl;
+
+namespace cppu_threadpool
+{
+ WaitingThread::WaitingThread(
+ rtl::Reference<ORequestThread> theThread): thread(std::move(theThread))
+ {}
+
+ DisposedCallerAdminHolder const & DisposedCallerAdmin::getInstance()
+ {
+ static DisposedCallerAdminHolder theDisposedCallerAdmin = std::make_shared<DisposedCallerAdmin>();
+ return theDisposedCallerAdmin;
+ }
+
+ DisposedCallerAdmin::~DisposedCallerAdmin()
+ {
+ SAL_WARN_IF( !m_vector.empty(), "cppu.threadpool", "DisposedCallerList : " << m_vector.size() << " left");
+ }
+
+ void DisposedCallerAdmin::dispose( void const * nDisposeId )
+ {
+ std::scoped_lock guard( m_mutex );
+ m_vector.push_back( nDisposeId );
+ }
+
+ void DisposedCallerAdmin::destroy( void const * nDisposeId )
+ {
+ std::scoped_lock guard( m_mutex );
+ m_vector.erase(std::remove(m_vector.begin(), m_vector.end(), nDisposeId), m_vector.end());
+ }
+
+ bool DisposedCallerAdmin::isDisposed( void const * nDisposeId )
+ {
+ std::scoped_lock guard( m_mutex );
+ return (std::find(m_vector.begin(), m_vector.end(), nDisposeId) != m_vector.end());
+ }
+
+
+ ThreadPool::ThreadPool() :
+ m_DisposedCallerAdmin( DisposedCallerAdmin::getInstance() )
+ {
+ }
+
+ ThreadPool::~ThreadPool()
+ {
+ SAL_WARN_IF( m_mapQueue.size(), "cppu.threadpool", "ThreadIdHashMap: " << m_mapQueue.size() << " left");
+ }
+
+ void ThreadPool::dispose( void const * nDisposeId )
+ {
+ m_DisposedCallerAdmin->dispose( nDisposeId );
+
+ std::scoped_lock guard( m_mutex );
+ for (auto const& item : m_mapQueue)
+ {
+ if( item.second.first )
+ {
+ item.second.first->dispose( nDisposeId );
+ }
+ if( item.second.second )
+ {
+ item.second.second->dispose( nDisposeId );
+ }
+ }
+ }
+
+ void ThreadPool::destroy( void const * nDisposeId )
+ {
+ m_DisposedCallerAdmin->destroy( nDisposeId );
+ }
+
+ /******************
+ * This methods lets the thread wait a certain amount of time. If within this timespan
+ * a new request comes in, this thread is reused. This is done only to improve performance,
+ * it is not required for threadpool functionality.
+ ******************/
+ void ThreadPool::waitInPool( rtl::Reference< ORequestThread > const & pThread )
+ {
+ WaitingThread waitingThread(pThread);
+ {
+ std::scoped_lock guard( m_mutexWaitingThreadList );
+ m_dequeThreads.push_front( &waitingThread );
+ }
+
+ // let the thread wait 2 seconds
+ waitingThread.condition.wait( std::chrono::seconds(2) );
+
+ {
+ std::scoped_lock guard ( m_mutexWaitingThreadList );
+ if( waitingThread.thread.is() )
+ {
+ // thread wasn't reused, remove it from the list
+ WaitingThreadDeque::iterator ii = find(
+ m_dequeThreads.begin(), m_dequeThreads.end(), &waitingThread );
+ OSL_ASSERT( ii != m_dequeThreads.end() );
+ m_dequeThreads.erase( ii );
+ }
+ }
+ }
+
+ void ThreadPool::joinWorkers()
+ {
+ {
+ std::scoped_lock guard( m_mutexWaitingThreadList );
+ for (auto const& thread : m_dequeThreads)
+ {
+ // wake the threads up
+ thread->condition.set();
+ }
+ }
+ m_aThreadAdmin.join();
+ }
+
+ bool ThreadPool::createThread( JobQueue *pQueue ,
+ const ByteSequence &aThreadId,
+ bool bAsynchron )
+ {
+ {
+ // Can a thread be reused ?
+ std::scoped_lock guard( m_mutexWaitingThreadList );
+ if( ! m_dequeThreads.empty() )
+ {
+ // inform the thread and let it go
+ struct WaitingThread *pWaitingThread = m_dequeThreads.back();
+ pWaitingThread->thread->setTask( pQueue , aThreadId , bAsynchron );
+ pWaitingThread->thread = nullptr;
+
+ // remove from list
+ m_dequeThreads.pop_back();
+
+ // let the thread go
+ pWaitingThread->condition.set();
+ return true;
+ }
+ }
+
+ rtl::Reference pThread(
+ new ORequestThread( this, pQueue , aThreadId, bAsynchron) );
+ return pThread->launch();
+ }
+
+ bool ThreadPool::revokeQueue( const ByteSequence &aThreadId, bool bAsynchron )
+ {
+ std::scoped_lock guard( m_mutex );
+
+ ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId );
+ OSL_ASSERT( ii != m_mapQueue.end() );
+
+ if( bAsynchron )
+ {
+ if( ! (*ii).second.second->isEmpty() )
+ {
+ // another thread has put something into the queue
+ return false;
+ }
+
+ (*ii).second.second = nullptr;
+ if( (*ii).second.first )
+ {
+ // all oneway request have been processed, now
+ // synchronous requests may go on
+ (*ii).second.first->resume();
+ }
+ }
+ else
+ {
+ if( ! (*ii).second.first->isEmpty() )
+ {
+ // another thread has put something into the queue
+ return false;
+ }
+ (*ii).second.first = nullptr;
+ }
+
+ if( nullptr == (*ii).second.first && nullptr == (*ii).second.second )
+ {
+ m_mapQueue.erase( ii );
+ }
+
+ return true;
+ }
+
+
+ bool ThreadPool::addJob(
+ const ByteSequence &aThreadId ,
+ bool bAsynchron,
+ void *pThreadSpecificData,
+ RequestFun * doRequest,
+ void const * disposeId )
+ {
+ bool bCreateThread = false;
+ JobQueue *pQueue = nullptr;
+ {
+ std::scoped_lock guard( m_mutex );
+ if (m_DisposedCallerAdmin->isDisposed(disposeId)) {
+ return true;
+ }
+
+ ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId );
+
+ if( ii == m_mapQueue.end() )
+ {
+ m_mapQueue[ aThreadId ] = pair < JobQueue * , JobQueue * > ( nullptr , nullptr );
+ ii = m_mapQueue.find( aThreadId );
+ OSL_ASSERT( ii != m_mapQueue.end() );
+ }
+
+ if( bAsynchron )
+ {
+ if( ! (*ii).second.second )
+ {
+ (*ii).second.second = new JobQueue();
+ bCreateThread = true;
+ }
+ pQueue = (*ii).second.second;
+ }
+ else
+ {
+ if( ! (*ii).second.first )
+ {
+ (*ii).second.first = new JobQueue();
+ bCreateThread = true;
+ }
+ pQueue = (*ii).second.first;
+
+ if( (*ii).second.second && ( (*ii).second.second->isBusy() ) )
+ {
+ pQueue->suspend();
+ }
+ }
+ pQueue->add( pThreadSpecificData , doRequest );
+ }
+
+ return !bCreateThread || createThread( pQueue , aThreadId , bAsynchron);
+ }
+
+ void ThreadPool::prepare( const ByteSequence &aThreadId )
+ {
+ std::scoped_lock guard( m_mutex );
+
+ ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId );
+
+ if( ii == m_mapQueue.end() )
+ {
+ JobQueue *p = new JobQueue();
+ m_mapQueue[ aThreadId ] = pair< JobQueue * , JobQueue * > ( p , nullptr );
+ }
+ else if( nullptr == (*ii).second.first )
+ {
+ (*ii).second.first = new JobQueue();
+ }
+ }
+
+ void * ThreadPool::enter( const ByteSequence & aThreadId , void const * nDisposeId )
+ {
+ JobQueue *pQueue = nullptr;
+ {
+ std::scoped_lock guard( m_mutex );
+
+ ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId );
+
+ OSL_ASSERT( ii != m_mapQueue.end() );
+ pQueue = (*ii).second.first;
+ }
+
+ OSL_ASSERT( pQueue );
+ void *pReturn = pQueue->enter( nDisposeId );
+
+ if( pQueue->isCallstackEmpty() )
+ {
+ if( revokeQueue( aThreadId , false) )
+ {
+ // remove queue
+ delete pQueue;
+ }
+ }
+ return pReturn;
+ }
+}
+
+// All uno_ThreadPool handles in g_pThreadpoolHashSet with overlapping life
+// spans share one ThreadPool instance. When g_pThreadpoolHashSet becomes empty
+// (within the last uno_threadpool_destroy) all worker threads spawned by that
+// ThreadPool instance are joined (which implies that uno_threadpool_destroy
+// must never be called from a worker thread); afterwards, the next call to
+// uno_threadpool_create (if any) will lead to a new ThreadPool instance.
+
+using namespace cppu_threadpool;
+
+namespace {
+
+struct uno_ThreadPool_Equal
+{
+ bool operator () ( const uno_ThreadPool &a , const uno_ThreadPool &b ) const
+ {
+ return a == b;
+ }
+};
+
+struct uno_ThreadPool_Hash
+{
+ std::size_t operator () ( const uno_ThreadPool &a ) const
+ {
+ return reinterpret_cast<std::size_t>( a );
+ }
+};
+
+}
+
+typedef std::unordered_map< uno_ThreadPool, ThreadPoolHolder, uno_ThreadPool_Hash, uno_ThreadPool_Equal > ThreadpoolHashSet;
+
+static ThreadpoolHashSet *g_pThreadpoolHashSet;
+
+struct _uno_ThreadPool
+{
+ sal_Int32 dummy;
+};
+
+namespace {
+
+ThreadPoolHolder getThreadPool( uno_ThreadPool hPool )
+{
+ MutexGuard guard( Mutex::getGlobalMutex() );
+ assert( g_pThreadpoolHashSet != nullptr );
+ ThreadpoolHashSet::iterator i( g_pThreadpoolHashSet->find(hPool) );
+ assert( i != g_pThreadpoolHashSet->end() );
+ return i->second;
+}
+
+}
+
+extern "C" uno_ThreadPool SAL_CALL
+uno_threadpool_create() SAL_THROW_EXTERN_C()
+{
+ MutexGuard guard( Mutex::getGlobalMutex() );
+ ThreadPoolHolder p;
+ if( ! g_pThreadpoolHashSet )
+ {
+ g_pThreadpoolHashSet = new ThreadpoolHashSet;
+ p = new ThreadPool;
+ }
+ else
+ {
+ assert( !g_pThreadpoolHashSet->empty() );
+ p = g_pThreadpoolHashSet->begin()->second;
+ }
+
+ // Just ensure that the handle is unique in the process (via heap)
+ uno_ThreadPool h = new struct _uno_ThreadPool;
+ g_pThreadpoolHashSet->emplace( h, p );
+ return h;
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_attach( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C()
+{
+ sal_Sequence *pThreadId = nullptr;
+ uno_getIdOfCurrentThread( &pThreadId );
+ getThreadPool( hPool )->prepare( pThreadId );
+ rtl_byte_sequence_release( pThreadId );
+ uno_releaseIdFromCurrentThread();
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_enter( uno_ThreadPool hPool , void **ppJob )
+ SAL_THROW_EXTERN_C()
+{
+ sal_Sequence *pThreadId = nullptr;
+ uno_getIdOfCurrentThread( &pThreadId );
+ *ppJob =
+ getThreadPool( hPool )->enter(
+ pThreadId,
+ hPool );
+ rtl_byte_sequence_release( pThreadId );
+ uno_releaseIdFromCurrentThread();
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_detach(SAL_UNUSED_PARAMETER uno_ThreadPool) SAL_THROW_EXTERN_C()
+{
+ // we might do here some tidying up in case a thread called attach but never detach
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_putJob(
+ uno_ThreadPool hPool,
+ sal_Sequence *pThreadId,
+ void *pJob,
+ void ( SAL_CALL * doRequest ) ( void *pThreadSpecificData ),
+ sal_Bool bIsOneway ) SAL_THROW_EXTERN_C()
+{
+ if (!getThreadPool(hPool)->addJob( pThreadId, bIsOneway, pJob ,doRequest, hPool ))
+ {
+ SAL_WARN(
+ "cppu.threadpool",
+ "uno_threadpool_putJob in parallel with uno_threadpool_destroy");
+ }
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_dispose( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C()
+{
+ getThreadPool(hPool)->dispose(
+ hPool );
+}
+
+extern "C" void SAL_CALL
+uno_threadpool_destroy( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C()
+{
+ ThreadPoolHolder p( getThreadPool(hPool) );
+ p->destroy(
+ hPool );
+
+ bool empty;
+ {
+ OSL_ASSERT( g_pThreadpoolHashSet );
+
+ MutexGuard guard( Mutex::getGlobalMutex() );
+
+ ThreadpoolHashSet::iterator ii = g_pThreadpoolHashSet->find( hPool );
+ OSL_ASSERT( ii != g_pThreadpoolHashSet->end() );
+ g_pThreadpoolHashSet->erase( ii );
+ delete hPool;
+
+ empty = g_pThreadpoolHashSet->empty();
+ if( empty )
+ {
+ delete g_pThreadpoolHashSet;
+ g_pThreadpoolHashSet = nullptr;
+ }
+ }
+
+ if( empty )
+ {
+ p->joinWorkers();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/threadpool/threadpool.hxx b/cppu/source/threadpool/threadpool.hxx
new file mode 100644
index 000000000..afcae7a7e
--- /dev/null
+++ b/cppu/source/threadpool/threadpool.hxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <mutex>
+#include <vector>
+#include <unordered_map>
+
+#include <osl/conditn.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/byteseq.hxx>
+#include <rtl/ref.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+#include "jobqueue.hxx"
+
+
+namespace cppu_threadpool {
+ class ORequestThread;
+
+ struct EqualThreadId
+ {
+ bool operator () ( const ::rtl::ByteSequence &a , const ::rtl::ByteSequence &b ) const
+ {
+ return a == b;
+ }
+ };
+
+ struct HashThreadId
+ {
+ sal_Int32 operator () ( const ::rtl::ByteSequence &a ) const
+ {
+ if( a.getLength() >= 4 )
+ {
+ return *reinterpret_cast<sal_Int32 const *>(a.getConstArray());
+ }
+ return 0;
+ }
+ };
+
+ typedef std::unordered_map
+ <
+ ::rtl::ByteSequence, // ThreadID
+ std::pair < JobQueue * , JobQueue * >,
+ HashThreadId,
+ EqualThreadId
+ > ThreadIdHashMap;
+
+ struct WaitingThread
+ {
+ osl::Condition condition;
+ rtl::Reference< ORequestThread > thread;
+
+ explicit WaitingThread(
+ rtl::Reference<ORequestThread> theThread);
+ };
+
+ typedef std::deque< struct ::cppu_threadpool::WaitingThread * > WaitingThreadDeque;
+
+ class DisposedCallerAdmin;
+ typedef std::shared_ptr<DisposedCallerAdmin> DisposedCallerAdminHolder;
+
+ class DisposedCallerAdmin
+ {
+ public:
+ ~DisposedCallerAdmin();
+
+ static DisposedCallerAdminHolder const & getInstance();
+
+ void dispose( void const * nDisposeId );
+ void destroy( void const * nDisposeId );
+ bool isDisposed( void const * nDisposeId );
+
+ private:
+ std::mutex m_mutex;
+ std::vector< void const * > m_vector;
+ };
+
+ class ThreadAdmin
+ {
+ public:
+ ThreadAdmin();
+ ~ThreadAdmin ();
+
+ void remove( rtl::Reference< ORequestThread > const & );
+ void join();
+
+ bool add_locked( rtl::Reference< ORequestThread > const & );
+ void remove_locked( rtl::Reference< ORequestThread > const & );
+ std::mutex m_mutex;
+
+ private:
+ std::deque< rtl::Reference< ORequestThread > > m_deque;
+ bool m_disposed;
+ };
+
+ class ThreadPool;
+ typedef rtl::Reference<ThreadPool> ThreadPoolHolder;
+
+ class ThreadPool: public salhelper::SimpleReferenceObject
+ {
+ public:
+ ThreadPool();
+ virtual ~ThreadPool() override;
+
+ void dispose( void const * nDisposeId );
+ void destroy( void const * nDisposeId );
+
+ bool addJob( const ::rtl::ByteSequence &aThreadId,
+ bool bAsynchron,
+ void *pThreadSpecificData,
+ RequestFun * doRequest,
+ void const * disposeId );
+
+ void prepare( const ::rtl::ByteSequence &aThreadId );
+ void * enter( const ::rtl::ByteSequence &aThreadId, void const * nDisposeId );
+
+ /********
+ * @return true, if queue could be successfully revoked.
+ ********/
+ bool revokeQueue( const ::rtl::ByteSequence & aThreadId , bool bAsynchron );
+
+ void waitInPool( rtl::Reference< ORequestThread > const & pThread );
+
+ void joinWorkers();
+
+ ThreadAdmin & getThreadAdmin() { return m_aThreadAdmin; }
+
+ private:
+ bool createThread( JobQueue *pQueue, const ::rtl::ByteSequence &aThreadId, bool bAsynchron);
+
+
+ ThreadIdHashMap m_mapQueue;
+ std::mutex m_mutex;
+
+ std::mutex m_mutexWaitingThreadList;
+ WaitingThreadDeque m_dequeThreads;
+
+ DisposedCallerAdminHolder m_DisposedCallerAdmin;
+ ThreadAdmin m_aThreadAdmin;
+ };
+
+} // end namespace cppu_threadpool
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/typelib/static_types.cxx b/cppu/source/typelib/static_types.cxx
new file mode 100644
index 000000000..6b9a35ac9
--- /dev/null
+++ b/cppu/source/typelib/static_types.cxx
@@ -0,0 +1,555 @@
+/* -*- 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 <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+
+#include <typelib/typedescription.h>
+#include "typelib.hxx"
+
+
+using namespace osl;
+
+namespace
+{
+ Mutex& typelib_StaticInitMutex()
+ {
+ static Mutex SINGLETON;
+ return SINGLETON;
+ }
+}
+
+extern "C"
+{
+
+
+#ifdef _WIN32
+#pragma pack(push, 8)
+#endif
+
+namespace {
+
+/**
+ * The double member determines the alignment.
+ * Under OS2 and MS-Windows the Alignment is min( 8, sizeof( type ) ).
+ * The alignment of a structure is min( 8, sizeof( max basic type ) ), the greatest basic type
+ * determines the alignment.
+ */
+struct AlignSize_Impl
+{
+ sal_Int16 nInt16;
+#ifdef AIX
+ //double: doubleword aligned if -qalign=natural/-malign=natural
+ //which isn't the default ABI. Otherwise word aligned, While a long long int
+ //is always doubleword aligned, so use that instead.
+ sal_Int64 dDouble;
+#else
+ double dDouble;
+#endif
+};
+
+}
+
+#ifdef _WIN32
+#pragma pack(pop)
+#endif
+
+// the value of the maximal alignment
+const sal_Int32 nMaxAlignment = static_cast<sal_Int32>( reinterpret_cast<sal_Size>(&reinterpret_cast<AlignSize_Impl *>(16)->dDouble) - 16);
+
+static sal_Int32 adjustAlignment( sal_Int32 nRequestedAlignment )
+{
+ if( nRequestedAlignment > nMaxAlignment )
+ nRequestedAlignment = nMaxAlignment;
+ return nRequestedAlignment;
+}
+
+/**
+ * Calculate the new size of the struktur.
+ */
+static sal_Int32 newAlignedSize(
+ sal_Int32 OldSize, sal_Int32 ElementSize, sal_Int32 NeededAlignment )
+{
+ NeededAlignment = adjustAlignment( NeededAlignment );
+ return (OldSize + NeededAlignment -1) / NeededAlignment * NeededAlignment + ElementSize;
+}
+
+
+// !for NOT REALLY WEAK TYPES only!
+static typelib_TypeDescriptionReference * igetTypeByName( rtl_uString const * pTypeName )
+{
+ typelib_TypeDescriptionReference * pRef = nullptr;
+ ::typelib_typedescriptionreference_getByName( &pRef, pTypeName );
+ if (pRef && pRef->pType && pRef->pType->pWeakRef) // found initialized td
+ {
+ return pRef;
+ }
+ return nullptr;
+}
+
+extern "C"
+{
+
+typelib_TypeDescriptionReference ** SAL_CALL typelib_static_type_getByTypeClass(
+ typelib_TypeClass eTypeClass )
+ SAL_THROW_EXTERN_C()
+{
+ static typelib_TypeDescriptionReference * s_aTypes[] = {
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr };
+
+ if (! s_aTypes[eTypeClass])
+ {
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if (! s_aTypes[eTypeClass])
+ {
+ static const char * s_aTypeNames[] = {
+ "void", "char", "boolean", "byte",
+ "short", "unsigned short", "long", "unsigned long",
+ "hyper", "unsigned hyper", "float", "double",
+ "string", "type", "any" };
+
+ switch (eTypeClass)
+ {
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_INTERFACE:
+ {
+ // type
+ if (! s_aTypes[typelib_TypeClass_TYPE])
+ {
+ OUString sTypeName("type");
+ ::typelib_typedescriptionreference_new(
+ &s_aTypes[typelib_TypeClass_TYPE], typelib_TypeClass_TYPE, sTypeName.pData );
+ // another static ref:
+ ++s_aTypes[typelib_TypeClass_TYPE]->nStaticRefCount;
+ }
+ // any
+ if (! s_aTypes[typelib_TypeClass_ANY])
+ {
+ OUString sTypeName("any");
+ ::typelib_typedescriptionreference_new(
+ &s_aTypes[typelib_TypeClass_ANY], typelib_TypeClass_ANY, sTypeName.pData );
+ // another static ref:
+ ++s_aTypes[typelib_TypeClass_ANY]->nStaticRefCount;
+ }
+ // string
+ if (! s_aTypes[typelib_TypeClass_STRING])
+ {
+ OUString sTypeName("string");
+ ::typelib_typedescriptionreference_new(
+ &s_aTypes[typelib_TypeClass_STRING], typelib_TypeClass_STRING, sTypeName.pData );
+ // another static ref:
+ ++s_aTypes[typelib_TypeClass_STRING]->nStaticRefCount;
+ }
+ // XInterface
+ if (! s_aTypes[typelib_TypeClass_INTERFACE])
+ {
+ OUString sTypeName("com.sun.star.uno.XInterface");
+
+ typelib_InterfaceTypeDescription * pTD = nullptr;
+
+ typelib_TypeDescriptionReference * pMembers[3] = { nullptr,nullptr,nullptr };
+ OUString sMethodName0("com.sun.star.uno.XInterface::queryInterface");
+ ::typelib_typedescriptionreference_new(
+ &pMembers[0], typelib_TypeClass_INTERFACE_METHOD, sMethodName0.pData );
+ OUString sMethodName1("com.sun.star.uno.XInterface::acquire");
+ ::typelib_typedescriptionreference_new(
+ &pMembers[1], typelib_TypeClass_INTERFACE_METHOD, sMethodName1.pData );
+ OUString sMethodName2("com.sun.star.uno.XInterface::release");
+ ::typelib_typedescriptionreference_new(
+ &pMembers[2], typelib_TypeClass_INTERFACE_METHOD, sMethodName2.pData );
+
+ ::typelib_typedescription_newInterface(
+ &pTD, sTypeName.pData, 0, 0, 0, 0, 0, nullptr, 3, pMembers );
+
+ ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription **>(&pTD) );
+ s_aTypes[typelib_TypeClass_INTERFACE] = pTD->aBase.pWeakRef;
+ ::typelib_typedescriptionreference_acquire(
+ s_aTypes[typelib_TypeClass_INTERFACE] );
+ // another static ref:
+ ++s_aTypes[typelib_TypeClass_INTERFACE]->nStaticRefCount;
+ ::typelib_typedescription_release( &pTD->aBase );
+
+ ::typelib_typedescriptionreference_release( pMembers[0] );
+ ::typelib_typedescriptionreference_release( pMembers[1] );
+ ::typelib_typedescriptionreference_release( pMembers[2] );
+ // Exception
+ assert( ! s_aTypes[typelib_TypeClass_EXCEPTION] );
+ {
+ typelib_TypeDescription * pTD1 = nullptr;
+ OUString sTypeName1("com.sun.star.uno.Exception");
+
+ typelib_CompoundMember_Init aMembers[2];
+ OUString sMemberType0("string");
+ OUString sMemberName0("Message");
+ aMembers[0].eTypeClass = typelib_TypeClass_STRING;
+ aMembers[0].pTypeName = sMemberType0.pData;
+ aMembers[0].pMemberName = sMemberName0.pData;
+ OUString sMemberType1("com.sun.star.uno.XInterface");
+ OUString sMemberName1("Context");
+ aMembers[1].eTypeClass = typelib_TypeClass_INTERFACE;
+ aMembers[1].pTypeName = sMemberType1.pData;
+ aMembers[1].pMemberName = sMemberName1.pData;
+
+ ::typelib_typedescription_new(
+ &pTD1, typelib_TypeClass_EXCEPTION, sTypeName1.pData, nullptr, 2, aMembers );
+ typelib_typedescription_register( &pTD1 );
+ s_aTypes[typelib_TypeClass_EXCEPTION] = pTD1->pWeakRef;
+ typelib_typedescriptionreference_acquire(
+ s_aTypes[typelib_TypeClass_EXCEPTION]);
+ // another static ref:
+ ++s_aTypes[typelib_TypeClass_EXCEPTION]->nStaticRefCount;
+ // RuntimeException
+ OUString sTypeName2("com.sun.star.uno.RuntimeException");
+ ::typelib_typedescription_new(
+ &pTD1, typelib_TypeClass_EXCEPTION, sTypeName2.pData, s_aTypes[typelib_TypeClass_EXCEPTION], 0, nullptr );
+ ::typelib_typedescription_register( &pTD1 );
+ ::typelib_typedescription_release( pTD1 );
+ }
+ // XInterface members
+ typelib_InterfaceMethodTypeDescription * pMethod = nullptr;
+ typelib_Parameter_Init aParameters[1];
+ OUString sParamName0("aType");
+ OUString sParamType0("type");
+ aParameters[0].pParamName = sParamName0.pData;
+ aParameters[0].eTypeClass = typelib_TypeClass_TYPE;
+ aParameters[0].pTypeName = sParamType0.pData;
+ aParameters[0].bIn = true;
+ aParameters[0].bOut = false;
+ rtl_uString * pExceptions[1];
+ OUString sExceptionName0("com.sun.star.uno.RuntimeException");
+ pExceptions[0] = sExceptionName0.pData;
+ OUString sReturnType0("any");
+ typelib_typedescription_newInterfaceMethod(
+ &pMethod, 0, false, sMethodName0.pData,
+ typelib_TypeClass_ANY, sReturnType0.pData,
+ 1, aParameters, 1, pExceptions );
+ ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) );
+
+ OUString sReturnType1("void");
+ ::typelib_typedescription_newInterfaceMethod(
+ &pMethod, 1, true, sMethodName1.pData,
+ typelib_TypeClass_VOID, sReturnType1.pData, 0, nullptr, 0, nullptr );
+ ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) );
+
+ ::typelib_typedescription_newInterfaceMethod(
+ &pMethod, 2, true, sMethodName2.pData,
+ typelib_TypeClass_VOID, sReturnType1.pData,
+ 0, nullptr, 0, nullptr );
+ ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) );
+ ::typelib_typedescription_release( &pMethod->aBase.aBase );
+ }
+ break;
+ }
+ default:
+ {
+ OUString aTypeName( OUString::createFromAscii( s_aTypeNames[eTypeClass] ) );
+ ::typelib_typedescriptionreference_new( &s_aTypes[eTypeClass], eTypeClass, aTypeName.pData );
+ // another static ref:
+ ++s_aTypes[eTypeClass]->nStaticRefCount;
+ }
+ }
+ }
+ }
+ return &s_aTypes[eTypeClass];
+}
+
+void SAL_CALL typelib_static_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ typelib_TypeClass eTypeClass, const char * pTypeName )
+ SAL_THROW_EXTERN_C()
+{
+ if (! *ppRef)
+ {
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if (! *ppRef)
+ {
+ OUString aTypeName( OUString::createFromAscii( pTypeName ) );
+ ::typelib_typedescriptionreference_new( ppRef, eTypeClass, aTypeName.pData );
+
+ assert(*ppRef && "coverity[var_deref_op] - shouldn't be possible");
+ ++((*ppRef)->nStaticRefCount);
+ }
+ }
+}
+
+void SAL_CALL typelib_static_sequence_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ typelib_TypeDescriptionReference * pElementType )
+ SAL_THROW_EXTERN_C()
+{
+ if ( *ppRef)
+ return;
+
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if ( *ppRef)
+ return;
+
+ OUString aTypeName = "[]" + OUString::unacquired(&pElementType->pTypeName);
+
+ static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_SEQUENCE) );
+ *ppRef = igetTypeByName( aTypeName.pData );
+ if (!*ppRef)
+ {
+ typelib_TypeDescription * pReg = nullptr;
+ ::typelib_typedescription_new(
+ &pReg, typelib_TypeClass_SEQUENCE,
+ aTypeName.pData, pElementType, 0, nullptr );
+
+ ::typelib_typedescription_register( &pReg );
+ *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ assert( *ppRef == pReg->pWeakRef );
+ }
+ // another static ref:
+ ++((*ppRef)->nStaticRefCount);
+}
+
+
+namespace {
+
+void init(
+ typelib_TypeDescriptionReference ** ppRef,
+ typelib_TypeClass eTypeClass, const char * pTypeName,
+ typelib_TypeDescriptionReference * pBaseType,
+ sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers,
+ sal_Bool const * pParameterizedTypes)
+{
+ assert( eTypeClass == typelib_TypeClass_STRUCT || eTypeClass == typelib_TypeClass_EXCEPTION );
+
+ if ( *ppRef)
+ return;
+
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if ( *ppRef)
+ return;
+
+ assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(eTypeClass) );
+ OUString aTypeName( OUString::createFromAscii( pTypeName ) );
+ *ppRef = igetTypeByName( aTypeName.pData );
+ if (!*ppRef)
+ {
+ typelib_CompoundTypeDescription * pComp = nullptr;
+ ::typelib_typedescription_newEmpty(
+ reinterpret_cast<typelib_TypeDescription **>(&pComp), eTypeClass, aTypeName.pData );
+
+ sal_Int32 nOffset = 0;
+ if (pBaseType)
+ {
+ ::typelib_typedescriptionreference_getDescription(
+ reinterpret_cast<typelib_TypeDescription **>(&pComp->pBaseTypeDescription), pBaseType );
+ assert( pComp->pBaseTypeDescription );
+ nOffset = pComp->pBaseTypeDescription->aBase.nSize;
+ assert( newAlignedSize( 0, pComp->pBaseTypeDescription->aBase.nSize, pComp->pBaseTypeDescription->aBase.nAlignment ) == pComp->pBaseTypeDescription->aBase.nSize ); // unexpected offset
+ }
+
+ if (nMembers)
+ {
+ pComp->nMembers = nMembers;
+ pComp->pMemberOffsets = new sal_Int32[ nMembers ];
+ pComp->ppTypeRefs = new typelib_TypeDescriptionReference *[ nMembers ];
+ if (pParameterizedTypes != nullptr) {
+ reinterpret_cast< typelib_StructTypeDescription * >(
+ pComp)->pParameterizedTypes
+ = new sal_Bool[nMembers];
+ }
+ for ( sal_Int32 i = 0 ; i < nMembers; ++i )
+ {
+ pComp->ppTypeRefs[i] = ppMembers[i];
+ ::typelib_typedescriptionreference_acquire(
+ pComp->ppTypeRefs[i] );
+ // write offset
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pComp->ppTypeRefs[i] );
+ assert( pTD->nSize ); // void member?
+ nOffset = newAlignedSize( nOffset, pTD->nSize, pTD->nAlignment );
+ pComp->pMemberOffsets[i] = nOffset - pTD->nSize;
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ if (pParameterizedTypes != nullptr) {
+ reinterpret_cast< typelib_StructTypeDescription * >(
+ pComp)->pParameterizedTypes[i]
+ = pParameterizedTypes[i];
+ }
+ }
+ }
+
+ typelib_TypeDescription * pReg = &pComp->aBase;
+ pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ // sizeof(void) not allowed
+ pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment );
+ pReg->nAlignment = adjustAlignment( pReg->nAlignment );
+ pReg->bComplete = false;
+
+ ::typelib_typedescription_register( &pReg );
+ *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ assert( *ppRef == pReg->pWeakRef );
+ }
+ // another static ref:
+ ++((*ppRef)->nStaticRefCount);
+}
+
+}
+
+void SAL_CALL typelib_static_compound_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ typelib_TypeClass eTypeClass, const char * pTypeName,
+ typelib_TypeDescriptionReference * pBaseType,
+ sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers )
+ SAL_THROW_EXTERN_C()
+{
+ init(ppRef, eTypeClass, pTypeName, pBaseType, nMembers, ppMembers, nullptr);
+}
+
+void SAL_CALL typelib_static_struct_type_init(
+ typelib_TypeDescriptionReference ** ppRef, const char * pTypeName,
+ typelib_TypeDescriptionReference * pBaseType,
+ sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers,
+ sal_Bool const * pParameterizedTypes )
+ SAL_THROW_EXTERN_C()
+{
+ init(
+ ppRef, typelib_TypeClass_STRUCT, pTypeName, pBaseType, nMembers,
+ ppMembers, pParameterizedTypes);
+}
+
+void SAL_CALL typelib_static_interface_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ const char * pTypeName,
+ typelib_TypeDescriptionReference * pBaseType )
+ SAL_THROW_EXTERN_C()
+{
+ // coverity[callee_ptr_arith] - not a bug
+ typelib_static_mi_interface_type_init(
+ ppRef, pTypeName, pBaseType == nullptr ? 0 : 1, &pBaseType);
+}
+
+void SAL_CALL typelib_static_mi_interface_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ const char * pTypeName,
+ sal_Int32 nBaseTypes,
+ typelib_TypeDescriptionReference ** ppBaseTypes )
+ SAL_THROW_EXTERN_C()
+{
+ if ( *ppRef)
+ return;
+
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if ( *ppRef)
+ return;
+
+ static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_INTERFACE) );
+ OUString aTypeName( OUString::createFromAscii( pTypeName ) );
+ *ppRef = igetTypeByName( aTypeName.pData );
+ if (!*ppRef)
+ {
+ typelib_InterfaceTypeDescription * pIface = nullptr;
+ ::typelib_typedescription_newEmpty(
+ reinterpret_cast<typelib_TypeDescription **>(&pIface), typelib_TypeClass_INTERFACE, aTypeName.pData );
+
+ pIface->nBaseTypes = std::max< sal_Int32 >(nBaseTypes, 1);
+ pIface->ppBaseTypes = new typelib_InterfaceTypeDescription *[
+ pIface->nBaseTypes];
+ if (nBaseTypes > 0)
+ {
+ for (sal_Int32 i = 0; i < nBaseTypes; ++i) {
+ pIface->ppBaseTypes[i] = nullptr;
+ ::typelib_typedescriptionreference_getDescription(
+ reinterpret_cast<typelib_TypeDescription **>(&pIface->ppBaseTypes[i]), ppBaseTypes[i] );
+ assert( pIface->ppBaseTypes[i] );
+ }
+ }
+ else
+ {
+ pIface->ppBaseTypes[0] = nullptr;
+ ::typelib_typedescriptionreference_getDescription(
+ reinterpret_cast<typelib_TypeDescription **>(&pIface->ppBaseTypes[0]),
+ * ::typelib_static_type_getByTypeClass( typelib_TypeClass_INTERFACE ) );
+ assert( pIface->ppBaseTypes[0] );
+ }
+ pIface->pBaseTypeDescription = pIface->ppBaseTypes[0];
+ typelib_typedescription_acquire(
+ &pIface->pBaseTypeDescription->aBase);
+
+ typelib_TypeDescription * pReg = &pIface->aBase;
+ pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ // sizeof(void) not allowed
+ pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment );
+
+ pReg->nAlignment = adjustAlignment( pReg->nAlignment );
+ pReg->bComplete = false;
+
+ ::typelib_typedescription_register( &pReg );
+ *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ assert( *ppRef == pReg->pWeakRef );
+ }
+ // another static ref:
+ ++((*ppRef)->nStaticRefCount);
+}
+
+
+void SAL_CALL typelib_static_enum_type_init(
+ typelib_TypeDescriptionReference ** ppRef,
+ const char * pTypeName,
+ sal_Int32 nDefaultValue )
+ SAL_THROW_EXTERN_C()
+{
+ if ( *ppRef)
+ return;
+
+ MutexGuard aGuard( typelib_StaticInitMutex() );
+ if ( *ppRef)
+ return;
+
+ static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_ENUM) );
+ OUString aTypeName( OUString::createFromAscii( pTypeName ) );
+ *ppRef = igetTypeByName( aTypeName.pData );
+ if (!*ppRef)
+ {
+ typelib_TypeDescription * pReg = nullptr;
+ ::typelib_typedescription_newEmpty(
+ &pReg, typelib_TypeClass_ENUM, aTypeName.pData );
+ typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(pReg);
+
+ pEnum->nDefaultEnumValue = nDefaultValue;
+
+ pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ // sizeof(void) not allowed
+ pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment );
+ pReg->nAlignment = ::adjustAlignment( pReg->nAlignment );
+ pReg->bComplete = false;
+
+ ::typelib_typedescription_register( &pReg );
+ *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg);
+ assert( *ppRef == pReg->pWeakRef );
+ }
+ // another static ref:
+ ++((*ppRef)->nStaticRefCount);
+}
+
+} // extern "C"
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/typelib/typelib.cxx b/cppu/source/typelib/typelib.cxx
new file mode 100644
index 000000000..293b4e324
--- /dev/null
+++ b/cppu/source/typelib/typelib.cxx
@@ -0,0 +1,2399 @@
+/* -*- 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 <algorithm>
+#include <unordered_map>
+#include <cassert>
+#include <list>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <stdlib.h>
+#include <string.h>
+#include <sal/log.hxx>
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <o3tl/string_view.hxx>
+#include "typelib.hxx"
+
+using namespace osl;
+
+#ifdef _WIN32
+#pragma pack(push, 8)
+#endif
+
+namespace {
+
+/**
+ * The double member determines the alignment.
+ * Under OS2 and MS-Windows the Alignment is min( 8, sizeof( type ) ).
+ * The alignment of a structure is min( 8, sizeof( max basic type ) ), the greatest basic type
+ * determines the alignment.
+ */
+struct AlignSize_Impl
+{
+ sal_Int16 nInt16;
+#ifdef AIX
+ //double: doubleword aligned if -qalign=natural/-malign=natural
+ //which isn't the default ABI. Otherwise word aligned, While a long long int
+ //is always doubleword aligned, so use that instead.
+ sal_Int64 dDouble;
+#else
+ double dDouble;
+#endif
+};
+
+}
+
+#ifdef _WIN32
+#pragma pack(pop)
+#endif
+
+// the value of the maximal alignment
+const sal_Int32 nMaxAlignment = static_cast<sal_Int32>( reinterpret_cast<sal_Size>(&reinterpret_cast<AlignSize_Impl *>(16)->dDouble) - 16);
+
+static sal_Int32 adjustAlignment( sal_Int32 nRequestedAlignment )
+{
+ if( nRequestedAlignment > nMaxAlignment )
+ nRequestedAlignment = nMaxAlignment;
+ return nRequestedAlignment;
+}
+
+/**
+ * Calculate the new size of the structure.
+ */
+static sal_Int32 newAlignedSize(
+ sal_Int32 OldSize, sal_Int32 ElementSize, sal_Int32 NeededAlignment )
+{
+ NeededAlignment = adjustAlignment( NeededAlignment );
+ return (OldSize + NeededAlignment -1) / NeededAlignment * NeededAlignment + ElementSize;
+}
+
+static sal_Int32 getDescriptionSize( typelib_TypeClass eTypeClass )
+{
+ OSL_ASSERT( typelib_TypeClass_TYPEDEF != eTypeClass );
+
+ sal_Int32 nSize;
+ // The reference is the description
+ // if the description is empty, then it must be filled with
+ // the new description
+ switch( eTypeClass )
+ {
+ case typelib_TypeClass_SEQUENCE:
+ nSize = sal_Int32(sizeof( typelib_IndirectTypeDescription ));
+ break;
+
+ case typelib_TypeClass_STRUCT:
+ nSize = sal_Int32(sizeof( typelib_StructTypeDescription ));
+ break;
+
+ case typelib_TypeClass_EXCEPTION:
+ nSize = sal_Int32(sizeof( typelib_CompoundTypeDescription ));
+ break;
+
+ case typelib_TypeClass_ENUM:
+ nSize = sal_Int32(sizeof( typelib_EnumTypeDescription ));
+ break;
+
+ case typelib_TypeClass_INTERFACE:
+ nSize = sal_Int32(sizeof( typelib_InterfaceTypeDescription ));
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ nSize = sal_Int32(sizeof( typelib_InterfaceMethodTypeDescription ));
+ break;
+
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ nSize = sal_Int32(sizeof( typelib_InterfaceAttributeTypeDescription ));
+ break;
+
+ default:
+ nSize = sal_Int32(sizeof( typelib_TypeDescription ));
+ }
+ return nSize;
+}
+
+namespace {
+
+struct equalStr_Impl
+{
+ bool operator()(const sal_Unicode * const & s1, const sal_Unicode * const & s2) const
+ { return 0 == rtl_ustr_compare( s1, s2 ); }
+};
+
+
+struct hashStr_Impl
+{
+ size_t operator()(const sal_Unicode * const & s) const
+ { return rtl_ustr_hashCode( s ); }
+};
+
+}
+
+// Heavy hack, the const sal_Unicode * is hold by the typedescription reference
+typedef std::unordered_map< const sal_Unicode *, typelib_TypeDescriptionReference *,
+ hashStr_Impl, equalStr_Impl > WeakMap_Impl;
+
+typedef std::pair< void *, typelib_typedescription_Callback > CallbackEntry;
+typedef std::list< CallbackEntry > CallbackSet_Impl;
+typedef std::list< typelib_TypeDescription * > TypeDescriptionList_Impl;
+
+// # of cached elements
+constexpr auto nCacheSize = 256;
+
+namespace {
+
+struct TypeDescriptor_Init_Impl
+{
+ // all type description references
+ WeakMap_Impl maWeakMap;
+ // all type description callbacks
+ CallbackSet_Impl maCallbacks;
+ // A cache to hold descriptions
+ TypeDescriptionList_Impl maCache;
+ // The mutex to guard all type library accesses
+ Mutex maMutex;
+
+ inline void callChain( typelib_TypeDescription ** ppRet, rtl_uString * pName );
+
+#if OSL_DEBUG_LEVEL > 0
+ // only for debugging
+ sal_Int32 nTypeDescriptionCount = 0;
+ sal_Int32 nCompoundTypeDescriptionCount = 0;
+ sal_Int32 nIndirectTypeDescriptionCount = 0;
+ sal_Int32 nEnumTypeDescriptionCount = 0;
+ sal_Int32 nInterfaceMethodTypeDescriptionCount = 0;
+ sal_Int32 nInterfaceAttributeTypeDescriptionCount = 0;
+ sal_Int32 nInterfaceTypeDescriptionCount = 0;
+ sal_Int32 nTypeDescriptionReferenceCount = 0;
+#endif
+
+ TypeDescriptor_Init_Impl() = default;
+
+ ~TypeDescriptor_Init_Impl();
+};
+
+}
+
+inline void TypeDescriptor_Init_Impl::callChain(
+ typelib_TypeDescription ** ppRet, rtl_uString * pName )
+{
+ assert(ppRet != nullptr);
+ assert(*ppRet == nullptr);
+ for( const CallbackEntry & rEntry : maCallbacks )
+ {
+ (*rEntry.second)( rEntry.first, ppRet, pName );
+ if( *ppRet )
+ return;
+ }
+}
+
+
+TypeDescriptor_Init_Impl::~TypeDescriptor_Init_Impl()
+{
+ for( typelib_TypeDescription* pItem : maCache )
+ {
+ typelib_typedescription_release( pItem );
+ }
+
+ {
+ std::vector< typelib_TypeDescriptionReference * > ppTDR;
+ ppTDR.reserve( maWeakMap.size() );
+
+ // save all weak references
+ for( const auto& rEntry : maWeakMap )
+ {
+ ppTDR.push_back( rEntry.second );
+ typelib_typedescriptionreference_acquire( ppTDR.back() );
+ }
+
+ for( typelib_TypeDescriptionReference * pTDR : ppTDR )
+ {
+ OSL_ASSERT( pTDR->nRefCount > pTDR->nStaticRefCount );
+ pTDR->nRefCount -= pTDR->nStaticRefCount;
+
+ if( pTDR->pType && !pTDR->pType->bOnDemand )
+ {
+ pTDR->pType->bOnDemand = true;
+ typelib_typedescription_release( pTDR->pType );
+ }
+ typelib_typedescriptionreference_release( pTDR );
+ }
+
+#if defined SAL_LOG_INFO
+ for( const auto& rEntry : maWeakMap )
+ {
+ typelib_TypeDescriptionReference * pTDR = rEntry.second;
+ if (pTDR)
+ {
+ OString aTypeName( OUStringToOString( OUString::unacquired(&pTDR->pTypeName), RTL_TEXTENCODING_ASCII_US ) );
+ SAL_INFO("cppu.typelib", "remaining type: " << aTypeName << "; ref count = " << pTDR->nRefCount);
+ }
+ else
+ {
+ SAL_INFO("cppu.typelib", "remaining null type entry!?");
+ }
+ }
+#endif
+ }
+#if OSL_DEBUG_LEVEL > 0
+ SAL_INFO_IF( nTypeDescriptionCount, "cppu.typelib", "nTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nCompoundTypeDescriptionCount, "cppu.typelib", "nCompoundTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nIndirectTypeDescriptionCount, "cppu.typelib", "nIndirectTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nEnumTypeDescriptionCount, "cppu.typelib", "nEnumTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nInterfaceMethodTypeDescriptionCount, "cppu.typelib", "nInterfaceMethodTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nInterfaceAttributeTypeDescriptionCount, "cppu.typelib", "nInterfaceAttributeTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nInterfaceTypeDescriptionCount, "cppu.typelib", "nInterfaceTypeDescriptionCount is not zero" );
+ SAL_INFO_IF( nTypeDescriptionReferenceCount, "cppu.typelib", "nTypeDescriptionReferenceCount is not zero" );
+#endif
+
+ SAL_INFO_IF( !maCallbacks.empty(), "cppu.typelib", "pCallbacks is not NULL or empty" );
+};
+
+namespace {
+TypeDescriptor_Init_Impl& Init()
+{
+ static TypeDescriptor_Init_Impl SINGLETON;
+ return SINGLETON;
+}
+}
+
+extern "C" void SAL_CALL typelib_typedescription_registerCallback(
+ void * pContext, typelib_typedescription_Callback pCallback )
+ SAL_THROW_EXTERN_C()
+{
+ // todo mt safe: guard is no solution, can not acquire while calling callback!
+ TypeDescriptor_Init_Impl &rInit = Init();
+// OslGuard aGuard( rInit.getMutex() );
+ rInit.maCallbacks.push_back( CallbackEntry( pContext, pCallback ) );
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_revokeCallback(
+ void * pContext, typelib_typedescription_Callback pCallback )
+ SAL_THROW_EXTERN_C()
+{
+ TypeDescriptor_Init_Impl &rInit = Init();
+ {
+ // todo mt safe: guard is no solution, can not acquire while calling callback!
+// OslGuard aGuard( rInit.getMutex() );
+ CallbackEntry aEntry( pContext, pCallback );
+ rInit.maCallbacks.erase(std::remove(rInit.maCallbacks.begin(), rInit.maCallbacks.end(), aEntry),
+ rInit.maCallbacks.end());
+ }
+}
+
+static void typelib_typedescription_initTables(
+ typelib_TypeDescription * pTD )
+{
+ typelib_InterfaceTypeDescription * pITD = reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD);
+
+ std::vector<bool> aReadWriteAttributes(pITD->nAllMembers);
+ for ( sal_Int32 i = pITD->nAllMembers; i--; )
+ {
+ aReadWriteAttributes[i] = false;
+ if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pITD->ppAllMembers[i]->eTypeClass )
+ {
+ typelib_TypeDescription * pM = nullptr;
+ TYPELIB_DANGER_GET( &pM, pITD->ppAllMembers[i] );
+ OSL_ASSERT( pM );
+ if (pM)
+ {
+ aReadWriteAttributes[i] = !reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(pM)->bReadOnly;
+ TYPELIB_DANGER_RELEASE( pM );
+ }
+ else
+ {
+ SAL_INFO( "cppu.typelib", "cannot get attribute type description: " << pITD->ppAllMembers[i]->pTypeName );
+ }
+ }
+ }
+
+ MutexGuard aGuard( Init().maMutex );
+ if( pTD->bComplete )
+ return;
+
+ // create the index table from member to function table
+ pITD->pMapMemberIndexToFunctionIndex = new sal_Int32[ pITD->nAllMembers ];
+ sal_Int32 nAdditionalOffset = 0; // +1 for read/write attributes
+ sal_Int32 i;
+ for( i = 0; i < pITD->nAllMembers; i++ )
+ {
+ // index to the get method of the attribute
+ pITD->pMapMemberIndexToFunctionIndex[i] = i + nAdditionalOffset;
+ // extra offset if it is a read/write attribute?
+ if (aReadWriteAttributes[i])
+ {
+ // a read/write attribute
+ nAdditionalOffset++;
+ }
+ }
+
+ // create the index table from function to member table
+ pITD->pMapFunctionIndexToMemberIndex = new sal_Int32[ pITD->nAllMembers + nAdditionalOffset ];
+ nAdditionalOffset = 0; // +1 for read/write attributes
+ for( i = 0; i < pITD->nAllMembers; i++ )
+ {
+ // index to the get method of the attribute
+ pITD->pMapFunctionIndexToMemberIndex[i + nAdditionalOffset] = i;
+ // extra offset if it is a read/write attribute?
+ if (aReadWriteAttributes[i])
+ {
+ // a read/write attribute
+ pITD->pMapFunctionIndexToMemberIndex[i + ++nAdditionalOffset] = i;
+ }
+ }
+ // must be the last action after all initialization is done
+ pITD->nMapFunctionIndexToMemberIndex = pITD->nAllMembers + nAdditionalOffset;
+ pTD->bComplete = true;
+}
+
+namespace {
+
+template<typename T> T * allocTypeDescription() {
+ return reinterpret_cast<T *>(new char[sizeof (T)]);
+}
+
+void freeTypeDescription(typelib_TypeDescription const * desc) {
+ delete[] reinterpret_cast<char const *>(desc);
+}
+
+// In some situations (notably typelib_typedescription_newInterfaceMethod and
+// typelib_typedescription_newInterfaceAttribute), only the members nMembers,
+// ppMembers, nAllMembers, and ppAllMembers of an incomplete interface type
+// description are necessary, but not the additional
+// pMapMemberIndexToFunctionIndex, nMapFunctionIndexToMemberIndex, and
+// pMapFunctionIndexToMemberIndex (which are computed by
+// typelib_typedescription_initTables). Furthermore, in those situations, it
+// might be illegal to compute those tables, as the creation of the interface
+// member type descriptions would recursively require a complete interface type
+// description. The parameter initTables controls whether or not to call
+// typelib_typedescription_initTables in those situations.
+bool complete(typelib_TypeDescription ** ppTypeDescr, bool initTables) {
+ if ((*ppTypeDescr)->bComplete)
+ return true;
+
+ OSL_ASSERT( (typelib_TypeClass_STRUCT == (*ppTypeDescr)->eTypeClass ||
+ typelib_TypeClass_EXCEPTION == (*ppTypeDescr)->eTypeClass ||
+ typelib_TypeClass_ENUM == (*ppTypeDescr)->eTypeClass ||
+ typelib_TypeClass_INTERFACE == (*ppTypeDescr)->eTypeClass) &&
+ !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppTypeDescr)->eTypeClass ) );
+
+ if (typelib_TypeClass_INTERFACE == (*ppTypeDescr)->eTypeClass &&
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(*ppTypeDescr)->ppAllMembers)
+ {
+ if (initTables) {
+ typelib_typedescription_initTables( *ppTypeDescr );
+ }
+ return true;
+ }
+
+ typelib_TypeDescription * pTD = nullptr;
+ // on demand access of complete td
+ TypeDescriptor_Init_Impl &rInit = Init();
+ rInit.callChain( &pTD, (*ppTypeDescr)->pTypeName );
+ if (pTD)
+ {
+ if (typelib_TypeClass_TYPEDEF == pTD->eTypeClass)
+ {
+ typelib_typedescriptionreference_getDescription(
+ &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
+ OSL_ASSERT( pTD );
+ if (! pTD)
+ return false;
+ }
+
+ OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTD->eTypeClass );
+ // typedescription found
+ // set to on demand
+ pTD->bOnDemand = true;
+
+ if (pTD->eTypeClass == typelib_TypeClass_INTERFACE
+ && !pTD->bComplete && initTables)
+ {
+ // mandatory info from callback chain
+ OSL_ASSERT( reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD)->ppAllMembers );
+ // complete except of tables init
+ typelib_typedescription_initTables( pTD );
+ pTD->bComplete = true;
+ }
+
+ // The type description is hold by the reference until
+ // on demand is activated.
+ ::typelib_typedescription_register( &pTD ); // replaces incomplete one
+ OSL_ASSERT( pTD == *ppTypeDescr ); // has to merge into existing one
+
+ // insert into the cache
+ MutexGuard aGuard( rInit.maMutex );
+ if( rInit.maCache.size() >= nCacheSize )
+ {
+ typelib_typedescription_release( rInit.maCache.front() );
+ rInit.maCache.pop_front();
+ }
+ // descriptions in the cache must be acquired!
+ typelib_typedescription_acquire( pTD );
+ rInit.maCache.push_back( pTD );
+
+ OSL_ASSERT(
+ pTD->bComplete
+ || (pTD->eTypeClass == typelib_TypeClass_INTERFACE
+ && !initTables));
+
+ ::typelib_typedescription_release( *ppTypeDescr );
+ *ppTypeDescr = pTD;
+ }
+ else
+ {
+ SAL_INFO(
+ "cppu.typelib",
+ "type cannot be completed: " << OUString::unacquired(&(*ppTypeDescr)->pTypeName));
+ return false;
+ }
+ return true;
+}
+
+}
+
+
+extern "C" void typelib_typedescription_newEmpty(
+ typelib_TypeDescription ** ppRet,
+ typelib_TypeClass eTypeClass, rtl_uString * pTypeName )
+ SAL_THROW_EXTERN_C()
+{
+ if( *ppRet )
+ {
+ typelib_typedescription_release( *ppRet );
+ *ppRet = nullptr;
+ }
+
+ OSL_ASSERT( typelib_TypeClass_TYPEDEF != eTypeClass );
+
+ typelib_TypeDescription * pRet;
+ switch( eTypeClass )
+ {
+ case typelib_TypeClass_SEQUENCE:
+ {
+ auto pTmp = allocTypeDescription<typelib_IndirectTypeDescription>();
+ pRet = &pTmp->aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nIndirectTypeDescriptionCount );
+#endif
+ pTmp->pType = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_STRUCT:
+ {
+ // FEATURE_EMPTYCLASS
+ auto pTmp = allocTypeDescription<typelib_StructTypeDescription>();
+ pRet = &pTmp->aBase.aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nCompoundTypeDescriptionCount );
+#endif
+ pTmp->aBase.pBaseTypeDescription = nullptr;
+ pTmp->aBase.nMembers = 0;
+ pTmp->aBase.pMemberOffsets = nullptr;
+ pTmp->aBase.ppTypeRefs = nullptr;
+ pTmp->aBase.ppMemberNames = nullptr;
+ pTmp->pParameterizedTypes = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_EXCEPTION:
+ {
+ // FEATURE_EMPTYCLASS
+ auto pTmp = allocTypeDescription<typelib_CompoundTypeDescription>();
+ pRet = &pTmp->aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nCompoundTypeDescriptionCount );
+#endif
+ pTmp->pBaseTypeDescription = nullptr;
+ pTmp->nMembers = 0;
+ pTmp->pMemberOffsets = nullptr;
+ pTmp->ppTypeRefs = nullptr;
+ pTmp->ppMemberNames = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_ENUM:
+ {
+ auto pTmp = allocTypeDescription<typelib_EnumTypeDescription>();
+ pRet = &pTmp->aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nEnumTypeDescriptionCount );
+#endif
+ pTmp->nDefaultEnumValue = 0;
+ pTmp->nEnumValues = 0;
+ pTmp->ppEnumNames = nullptr;
+ pTmp->pEnumValues = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE:
+ {
+ auto pTmp = allocTypeDescription<
+ typelib_InterfaceTypeDescription>();
+ pRet = &pTmp->aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nInterfaceTypeDescriptionCount );
+#endif
+ pTmp->pBaseTypeDescription = nullptr;
+ pTmp->nMembers = 0;
+ pTmp->ppMembers = nullptr;
+ pTmp->nAllMembers = 0;
+ pTmp->ppAllMembers = nullptr;
+ pTmp->nMapFunctionIndexToMemberIndex = 0;
+ pTmp->pMapFunctionIndexToMemberIndex = nullptr;
+ pTmp->pMapMemberIndexToFunctionIndex= nullptr;
+ pTmp->nBaseTypes = 0;
+ pTmp->ppBaseTypes = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ auto pTmp = allocTypeDescription<
+ typelib_InterfaceMethodTypeDescription>();
+ pRet = &pTmp->aBase.aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nInterfaceMethodTypeDescriptionCount );
+#endif
+ pTmp->aBase.pMemberName = nullptr;
+ pTmp->pReturnTypeRef = nullptr;
+ pTmp->nParams = 0;
+ pTmp->pParams = nullptr;
+ pTmp->nExceptions = 0;
+ pTmp->ppExceptions = nullptr;
+ pTmp->pInterface = nullptr;
+ pTmp->pBaseRef = nullptr;
+ pTmp->nIndex = 0;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ auto * pTmp = allocTypeDescription<
+ typelib_InterfaceAttributeTypeDescription>();
+ pRet = &pTmp->aBase.aBase;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nInterfaceAttributeTypeDescriptionCount );
+#endif
+ pTmp->aBase.pMemberName = nullptr;
+ pTmp->pAttributeTypeRef = nullptr;
+ pTmp->pInterface = nullptr;
+ pTmp->pBaseRef = nullptr;
+ pTmp->nIndex = 0;
+ pTmp->nGetExceptions = 0;
+ pTmp->ppGetExceptions = nullptr;
+ pTmp->nSetExceptions = 0;
+ pTmp->ppSetExceptions = nullptr;
+ // coverity[leaked_storage] - this is on purpose
+ }
+ break;
+
+ default:
+ {
+ pRet = allocTypeDescription<typelib_TypeDescription>();
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &Init().nTypeDescriptionCount );
+#endif
+ }
+ }
+
+ pRet->nRefCount = 1; // reference count is initially 1
+ pRet->nStaticRefCount = 0;
+ pRet->eTypeClass = eTypeClass;
+ pRet->pUniqueIdentifier = nullptr;
+ pRet->pReserved = nullptr;
+ pRet->pTypeName = pTypeName;
+ rtl_uString_acquire( pRet->pTypeName );
+ pRet->pSelf = pRet;
+ pRet->bComplete = true;
+ pRet->nSize = 0;
+ pRet->nAlignment = 0;
+ pRet->pWeakRef = nullptr;
+ pRet->bOnDemand = false;
+ *ppRet = pRet;
+}
+
+
+namespace {
+
+void newTypeDescription(
+ typelib_TypeDescription ** ppRet, typelib_TypeClass eTypeClass,
+ rtl_uString * pTypeName, typelib_TypeDescriptionReference * pType,
+ sal_Int32 nMembers, typelib_CompoundMember_Init * pCompoundMembers,
+ typelib_StructMember_Init * pStructMembers)
+{
+ OSL_ASSERT(
+ (pCompoundMembers == nullptr || pStructMembers == nullptr)
+ && (pStructMembers == nullptr || eTypeClass == typelib_TypeClass_STRUCT));
+ if (typelib_TypeClass_TYPEDEF == eTypeClass)
+ {
+ SAL_WARN("cppu.typelib", "unexpected typedef!" );
+ typelib_typedescriptionreference_getDescription( ppRet, pType );
+ return;
+ }
+
+ typelib_typedescription_newEmpty( ppRet, eTypeClass, pTypeName );
+
+ switch( eTypeClass )
+ {
+ case typelib_TypeClass_SEQUENCE:
+ {
+ OSL_ASSERT( nMembers == 0 );
+ typelib_typedescriptionreference_acquire( pType );
+ reinterpret_cast<typelib_IndirectTypeDescription *>(*ppRet)->pType = pType;
+ }
+ break;
+
+ case typelib_TypeClass_EXCEPTION:
+ case typelib_TypeClass_STRUCT:
+ {
+ // FEATURE_EMPTYCLASS
+ typelib_CompoundTypeDescription * pTmp = reinterpret_cast<typelib_CompoundTypeDescription*>(*ppRet);
+
+ sal_Int32 nOffset = 0;
+ if( pType )
+ {
+ typelib_typedescriptionreference_getDescription(
+ reinterpret_cast<typelib_TypeDescription **>(&pTmp->pBaseTypeDescription), pType );
+ nOffset = pTmp->pBaseTypeDescription->aBase.nSize;
+ OSL_ENSURE( newAlignedSize( 0, pTmp->pBaseTypeDescription->aBase.nSize, pTmp->pBaseTypeDescription->aBase.nAlignment ) == pTmp->pBaseTypeDescription->aBase.nSize, "### unexpected offset!" );
+ }
+ if( nMembers )
+ {
+ pTmp->nMembers = nMembers;
+ pTmp->pMemberOffsets = new sal_Int32[ nMembers ];
+ pTmp->ppTypeRefs = new typelib_TypeDescriptionReference *[ nMembers ];
+ pTmp->ppMemberNames = new rtl_uString *[ nMembers ];
+ bool polymorphic = eTypeClass == typelib_TypeClass_STRUCT
+ && OUString::unacquired(&pTypeName).indexOf('<') >= 0;
+ OSL_ASSERT(!polymorphic || pStructMembers != nullptr);
+ if (polymorphic) {
+ reinterpret_cast< typelib_StructTypeDescription * >(pTmp)->
+ pParameterizedTypes = new sal_Bool[nMembers];
+ }
+ for( sal_Int32 i = 0 ; i < nMembers; i++ )
+ {
+ // read the type and member names
+ pTmp->ppTypeRefs[i] = nullptr;
+ if (pCompoundMembers != nullptr) {
+ typelib_typedescriptionreference_new(
+ pTmp->ppTypeRefs +i, pCompoundMembers[i].eTypeClass,
+ pCompoundMembers[i].pTypeName );
+ pTmp->ppMemberNames[i]
+ = pCompoundMembers[i].pMemberName;
+ rtl_uString_acquire( pTmp->ppMemberNames[i] );
+ } else {
+ typelib_typedescriptionreference_new(
+ pTmp->ppTypeRefs +i,
+ pStructMembers[i].aBase.eTypeClass,
+ pStructMembers[i].aBase.pTypeName );
+ pTmp->ppMemberNames[i]
+ = pStructMembers[i].aBase.pMemberName;
+ rtl_uString_acquire(pTmp->ppMemberNames[i]);
+ }
+ // write offset
+ sal_Int32 size;
+ sal_Int32 alignment;
+ if (pTmp->ppTypeRefs[i]->eTypeClass ==
+ typelib_TypeClass_SEQUENCE)
+ {
+ // Take care of recursion like
+ // struct S { sequence<S> x; };
+ size = sizeof(void *);
+ alignment = adjustAlignment(size);
+ } else {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pTmp->ppTypeRefs[i] );
+ OSL_ENSURE( pTD->nSize, "### void member?" );
+ size = pTD->nSize;
+ alignment = pTD->nAlignment;
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ nOffset = newAlignedSize( nOffset, size, alignment );
+ pTmp->pMemberOffsets[i] = nOffset - size;
+
+ if (polymorphic) {
+ reinterpret_cast< typelib_StructTypeDescription * >(
+ pTmp)->pParameterizedTypes[i]
+ = pStructMembers[i].bParameterizedType;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( eTypeClass ) )
+ (*ppRet)->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppRet);
+ if( eTypeClass != typelib_TypeClass_VOID )
+ {
+ // sizeof(void) not allowed
+ (*ppRet)->nSize = typelib_typedescription_getAlignedUnoSize( (*ppRet), 0, (*ppRet)->nAlignment );
+ (*ppRet)->nAlignment = adjustAlignment( (*ppRet)->nAlignment );
+ }
+}
+
+}
+
+extern "C" void SAL_CALL typelib_typedescription_new(
+ typelib_TypeDescription ** ppRet,
+ typelib_TypeClass eTypeClass,
+ rtl_uString * pTypeName,
+ typelib_TypeDescriptionReference * pType,
+ sal_Int32 nMembers,
+ typelib_CompoundMember_Init * pMembers )
+ SAL_THROW_EXTERN_C()
+{
+ newTypeDescription(
+ ppRet, eTypeClass, pTypeName, pType, nMembers, pMembers, nullptr);
+}
+
+extern "C" void SAL_CALL typelib_typedescription_newStruct(
+ typelib_TypeDescription ** ppRet,
+ rtl_uString * pTypeName,
+ typelib_TypeDescriptionReference * pType,
+ sal_Int32 nMembers,
+ typelib_StructMember_Init * pMembers )
+ SAL_THROW_EXTERN_C()
+{
+ newTypeDescription(
+ ppRet, typelib_TypeClass_STRUCT, pTypeName, pType, nMembers, nullptr,
+ pMembers);
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_newEnum(
+ typelib_TypeDescription ** ppRet,
+ rtl_uString * pTypeName,
+ sal_Int32 nDefaultValue,
+ sal_Int32 nEnumValues,
+ rtl_uString ** ppEnumNames,
+ sal_Int32 * pEnumValues )
+ SAL_THROW_EXTERN_C()
+{
+ typelib_typedescription_newEmpty( ppRet, typelib_TypeClass_ENUM, pTypeName );
+ typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(*ppRet);
+
+ pEnum->nDefaultEnumValue = nDefaultValue;
+ pEnum->nEnumValues = nEnumValues;
+ pEnum->ppEnumNames = new rtl_uString * [ nEnumValues ];
+ for ( sal_Int32 nPos = nEnumValues; nPos--; )
+ {
+ pEnum->ppEnumNames[nPos] = ppEnumNames[nPos];
+ rtl_uString_acquire( pEnum->ppEnumNames[nPos] );
+ }
+ pEnum->pEnumValues = new sal_Int32[ nEnumValues ];
+ ::memcpy( pEnum->pEnumValues, pEnumValues, nEnumValues * sizeof(sal_Int32) );
+
+ static_assert(!TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_ENUM));
+ (*ppRet)->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppRet);
+ // sizeof(void) not allowed
+ (*ppRet)->nSize = typelib_typedescription_getAlignedUnoSize( (*ppRet), 0, (*ppRet)->nAlignment );
+ (*ppRet)->nAlignment = adjustAlignment( (*ppRet)->nAlignment );
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_newInterface(
+ typelib_InterfaceTypeDescription ** ppRet,
+ rtl_uString * pTypeName,
+ SAL_UNUSED_PARAMETER sal_uInt32, SAL_UNUSED_PARAMETER sal_uInt16,
+ SAL_UNUSED_PARAMETER sal_uInt16, SAL_UNUSED_PARAMETER sal_uInt32,
+ SAL_UNUSED_PARAMETER sal_uInt32,
+ typelib_TypeDescriptionReference * pBaseInterface,
+ sal_Int32 nMembers,
+ typelib_TypeDescriptionReference ** ppMembers )
+ SAL_THROW_EXTERN_C()
+{
+ // coverity[callee_ptr_arith] - not a bug
+ typelib_typedescription_newMIInterface(
+ ppRet, pTypeName, 0, 0, 0, 0, 0, pBaseInterface == nullptr ? 0 : 1,
+ &pBaseInterface, nMembers, ppMembers);
+}
+
+namespace {
+
+class BaseList {
+public:
+ struct Entry {
+ sal_Int32 memberOffset;
+ sal_Int32 directBaseIndex;
+ sal_Int32 directBaseMemberOffset;
+ typelib_InterfaceTypeDescription const * base;
+ };
+
+ typedef std::vector< Entry > List;
+
+ explicit BaseList(typelib_InterfaceTypeDescription const * desc);
+
+ List const & getList() const { return list; }
+
+ sal_Int32 getBaseMembers() const { return members; }
+
+private:
+ typedef std::set< OUString > Set;
+
+ void calculate(
+ Set& allSet,
+ sal_Int32 directBaseIndex, Set & directBaseSet,
+ sal_Int32 * directBaseMembers,
+ typelib_InterfaceTypeDescription const * desc);
+
+ List list;
+ sal_Int32 members;
+};
+
+BaseList::BaseList(typelib_InterfaceTypeDescription const * desc)
+ : members(0)
+{
+ Set allSet;
+ for (sal_Int32 i = 0; i < desc->nBaseTypes; ++i) {
+ Set directBaseSet;
+ sal_Int32 directBaseMembers = 0;
+ calculate(allSet, i, directBaseSet, &directBaseMembers, desc->ppBaseTypes[i]);
+ }
+}
+
+void BaseList::calculate(
+ Set& allSet,
+ sal_Int32 directBaseIndex, Set & directBaseSet,
+ sal_Int32 * directBaseMembers,
+ typelib_InterfaceTypeDescription const * desc)
+{
+ for (sal_Int32 i = 0; i < desc->nBaseTypes; ++i) {
+ calculate(allSet,
+ directBaseIndex, directBaseSet, directBaseMembers,
+ desc->ppBaseTypes[i]);
+ }
+ if (allSet.insert(desc->aBase.pTypeName).second) {
+ Entry e;
+ e.memberOffset = members;
+ e.directBaseIndex = directBaseIndex;
+ e.directBaseMemberOffset = *directBaseMembers;
+ e.base = desc;
+ list.push_back(e);
+ OSL_ASSERT(desc->ppAllMembers != nullptr);
+ members += desc->nMembers;
+ }
+ if (directBaseSet.insert(desc->aBase.pTypeName).second) {
+ OSL_ASSERT(desc->ppAllMembers != nullptr);
+ *directBaseMembers += desc->nMembers;
+ }
+}
+
+}
+
+extern "C" void SAL_CALL typelib_typedescription_newMIInterface(
+ typelib_InterfaceTypeDescription ** ppRet,
+ rtl_uString * pTypeName,
+ SAL_UNUSED_PARAMETER sal_uInt32, SAL_UNUSED_PARAMETER sal_uInt16,
+ SAL_UNUSED_PARAMETER sal_uInt16, SAL_UNUSED_PARAMETER sal_uInt32,
+ SAL_UNUSED_PARAMETER sal_uInt32,
+ sal_Int32 nBaseInterfaces,
+ typelib_TypeDescriptionReference ** ppBaseInterfaces,
+ sal_Int32 nMembers,
+ typelib_TypeDescriptionReference ** ppMembers )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppRet != nullptr) {
+ typelib_typedescription_release(&(*ppRet)->aBase);
+ *ppRet = nullptr;
+ }
+
+ typelib_InterfaceTypeDescription * pITD = nullptr;
+ typelib_typedescription_newEmpty(
+ reinterpret_cast<typelib_TypeDescription **>(&pITD), typelib_TypeClass_INTERFACE, pTypeName );
+
+ pITD->nBaseTypes = nBaseInterfaces;
+ pITD->ppBaseTypes = new typelib_InterfaceTypeDescription *[nBaseInterfaces];
+ for (sal_Int32 i = 0; i < nBaseInterfaces; ++i) {
+ pITD->ppBaseTypes[i] = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ reinterpret_cast< typelib_TypeDescription ** >(
+ &pITD->ppBaseTypes[i]),
+ ppBaseInterfaces[i]);
+ if (pITD->ppBaseTypes[i] == nullptr
+ || !complete(
+ reinterpret_cast< typelib_TypeDescription ** >(
+ &pITD->ppBaseTypes[i]),
+ false))
+ {
+ OSL_ASSERT(false);
+ return;
+ }
+ OSL_ASSERT(pITD->ppBaseTypes[i] != nullptr);
+ }
+ if (nBaseInterfaces > 0) {
+ pITD->pBaseTypeDescription = pITD->ppBaseTypes[0];
+ }
+ // set the
+ pITD->aUik.m_Data1 = 0;
+ pITD->aUik.m_Data2 = 0;
+ pITD->aUik.m_Data3 = 0;
+ pITD->aUik.m_Data4 = 0;
+ pITD->aUik.m_Data5 = 0;
+
+ BaseList aBaseList(pITD);
+ pITD->nAllMembers = nMembers + aBaseList.getBaseMembers();
+ pITD->nMembers = nMembers;
+
+ if( pITD->nAllMembers )
+ {
+ // at minimum one member exist, allocate the memory
+ pITD->ppAllMembers = new typelib_TypeDescriptionReference *[ pITD->nAllMembers ];
+ sal_Int32 n = 0;
+
+ BaseList::List const & rList = aBaseList.getList();
+ for (const auto& rEntry : rList)
+ {
+ typelib_InterfaceTypeDescription const * pBase = rEntry.base;
+ typelib_InterfaceTypeDescription const * pDirectBase
+ = pITD->ppBaseTypes[rEntry.directBaseIndex];
+ OSL_ASSERT(pBase->ppAllMembers != nullptr);
+ for (sal_Int32 j = 0; j < pBase->nMembers; ++j) {
+ typelib_TypeDescriptionReference const * pDirectBaseMember
+ = pDirectBase->ppAllMembers[rEntry.directBaseMemberOffset + j];
+ OUString aName = OUString::unacquired(&pDirectBaseMember->pTypeName) +
+ ":@" +
+ OUString::number(rEntry.directBaseIndex) +
+ "," +
+ OUString::number(rEntry.memberOffset + j) +
+ ":" +
+ OUString::unacquired(&pITD->aBase.pTypeName);
+ typelib_TypeDescriptionReference * pDerivedMember = nullptr;
+ typelib_typedescriptionreference_new(
+ &pDerivedMember, pDirectBaseMember->eTypeClass,
+ aName.pData);
+ pITD->ppAllMembers[n++] = pDerivedMember;
+ }
+ }
+
+ if( nMembers )
+ {
+ pITD->ppMembers = pITD->ppAllMembers + aBaseList.getBaseMembers();
+ }
+
+ // add own members
+ for( sal_Int32 i = 0; i < nMembers; i++ )
+ {
+ typelib_typedescriptionreference_acquire( ppMembers[i] );
+ pITD->ppAllMembers[n++] = ppMembers[i];
+ }
+ }
+
+ typelib_TypeDescription * pTmp = &pITD->aBase;
+ static_assert( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE ) );
+ pTmp->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pTmp);
+ pTmp->nSize = typelib_typedescription_getAlignedUnoSize( pTmp, 0, pTmp->nAlignment );
+ pTmp->nAlignment = adjustAlignment( pTmp->nAlignment );
+ pTmp->bComplete = false;
+
+ *ppRet = pITD;
+}
+
+
+namespace {
+
+typelib_TypeDescriptionReference ** copyExceptions(
+ sal_Int32 count, rtl_uString ** typeNames)
+{
+ OSL_ASSERT(count >= 0);
+ if (count == 0) {
+ return nullptr;
+ }
+ typelib_TypeDescriptionReference ** p
+ = new typelib_TypeDescriptionReference *[count];
+ for (sal_Int32 i = 0; i < count; ++i) {
+ p[i] = nullptr;
+ typelib_typedescriptionreference_new(
+ p + i, typelib_TypeClass_EXCEPTION, typeNames[i]);
+ }
+ return p;
+}
+
+}
+
+extern "C" void SAL_CALL typelib_typedescription_newInterfaceMethod(
+ typelib_InterfaceMethodTypeDescription ** ppRet,
+ sal_Int32 nAbsolutePosition,
+ sal_Bool bOneWay,
+ rtl_uString * pTypeName,
+ typelib_TypeClass eReturnTypeClass,
+ rtl_uString * pReturnTypeName,
+ sal_Int32 nParams,
+ typelib_Parameter_Init * pParams,
+ sal_Int32 nExceptions,
+ rtl_uString ** ppExceptionNames )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppRet != nullptr) {
+ typelib_typedescription_release(&(*ppRet)->aBase.aBase);
+ *ppRet = nullptr;
+ }
+ sal_Int32 nOffset = rtl_ustr_lastIndexOfChar_WithLength(
+ pTypeName->buffer, pTypeName->length, ':');
+ if (nOffset <= 0 || pTypeName->buffer[nOffset - 1] != ':') {
+ OSL_FAIL("Bad interface method type name");
+ return;
+ }
+ OUString aInterfaceTypeName(pTypeName->buffer, nOffset - 1);
+ typelib_InterfaceTypeDescription * pInterface = nullptr;
+ typelib_typedescription_getByName(
+ reinterpret_cast< typelib_TypeDescription ** >(&pInterface),
+ aInterfaceTypeName.pData);
+ if (pInterface == nullptr
+ || pInterface->aBase.eTypeClass != typelib_TypeClass_INTERFACE
+ || !complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&pInterface), false))
+ {
+ OSL_FAIL("No interface corresponding to interface method");
+ return;
+ }
+
+ typelib_typedescription_newEmpty(
+ reinterpret_cast<typelib_TypeDescription **>(ppRet), typelib_TypeClass_INTERFACE_METHOD, pTypeName );
+
+ rtl_uString_newFromStr_WithLength( &(*ppRet)->aBase.pMemberName,
+ pTypeName->buffer + nOffset +1,
+ pTypeName->length - nOffset -1 );
+ (*ppRet)->aBase.nPosition = nAbsolutePosition;
+ (*ppRet)->bOneWay = bOneWay;
+ typelib_typedescriptionreference_new( &(*ppRet)->pReturnTypeRef, eReturnTypeClass, pReturnTypeName );
+ (*ppRet)->nParams = nParams;
+ if( nParams )
+ {
+ (*ppRet)->pParams = new typelib_MethodParameter[ nParams ];
+
+ for( sal_Int32 i = 0; i < nParams; i++ )
+ {
+ // get the name of the parameter
+ (*ppRet)->pParams[ i ].pName = pParams[i].pParamName;
+ rtl_uString_acquire( (*ppRet)->pParams[ i ].pName );
+ (*ppRet)->pParams[ i ].pTypeRef = nullptr;
+ // get the type name of the parameter and create the weak reference
+ typelib_typedescriptionreference_new(
+ &(*ppRet)->pParams[ i ].pTypeRef, pParams[i].eTypeClass, pParams[i].pTypeName );
+ (*ppRet)->pParams[ i ].bIn = pParams[i].bIn;
+ (*ppRet)->pParams[ i ].bOut = pParams[i].bOut;
+ }
+ }
+ (*ppRet)->nExceptions = nExceptions;
+ (*ppRet)->ppExceptions = copyExceptions(nExceptions, ppExceptionNames);
+ (*ppRet)->pInterface = pInterface;
+ (*ppRet)->pBaseRef = nullptr;
+ OSL_ASSERT(
+ (nAbsolutePosition >= pInterface->nAllMembers - pInterface->nMembers)
+ && nAbsolutePosition < pInterface->nAllMembers);
+ (*ppRet)->nIndex = nAbsolutePosition
+ - (pInterface->nAllMembers - pInterface->nMembers);
+ static_assert( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE_METHOD ) );
+ assert(reinterpret_cast<typelib_TypeDescription *>(*ppRet)->pWeakRef == nullptr);
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_newInterfaceAttribute(
+ typelib_InterfaceAttributeTypeDescription ** ppRet,
+ sal_Int32 nAbsolutePosition,
+ rtl_uString * pTypeName,
+ typelib_TypeClass eAttributeTypeClass,
+ rtl_uString * pAttributeTypeName,
+ sal_Bool bReadOnly )
+ SAL_THROW_EXTERN_C()
+{
+ typelib_typedescription_newExtendedInterfaceAttribute(
+ ppRet, nAbsolutePosition, pTypeName, eAttributeTypeClass,
+ pAttributeTypeName, bReadOnly, 0, nullptr, 0, nullptr);
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_newExtendedInterfaceAttribute(
+ typelib_InterfaceAttributeTypeDescription ** ppRet,
+ sal_Int32 nAbsolutePosition,
+ rtl_uString * pTypeName,
+ typelib_TypeClass eAttributeTypeClass,
+ rtl_uString * pAttributeTypeName,
+ sal_Bool bReadOnly,
+ sal_Int32 nGetExceptions, rtl_uString ** ppGetExceptionNames,
+ sal_Int32 nSetExceptions, rtl_uString ** ppSetExceptionNames )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppRet != nullptr) {
+ typelib_typedescription_release(&(*ppRet)->aBase.aBase);
+ *ppRet = nullptr;
+ }
+ sal_Int32 nOffset = rtl_ustr_lastIndexOfChar_WithLength(
+ pTypeName->buffer, pTypeName->length, ':');
+ if (nOffset <= 0 || pTypeName->buffer[nOffset - 1] != ':') {
+ OSL_FAIL("Bad interface attribute type name");
+ return;
+ }
+ OUString aInterfaceTypeName(pTypeName->buffer, nOffset - 1);
+ typelib_InterfaceTypeDescription * pInterface = nullptr;
+ typelib_typedescription_getByName(
+ reinterpret_cast< typelib_TypeDescription ** >(&pInterface),
+ aInterfaceTypeName.pData);
+ if (pInterface == nullptr
+ || pInterface->aBase.eTypeClass != typelib_TypeClass_INTERFACE
+ || !complete(
+ reinterpret_cast< typelib_TypeDescription ** >(&pInterface), false))
+ {
+ OSL_FAIL("No interface corresponding to interface attribute");
+ return;
+ }
+
+ typelib_typedescription_newEmpty(
+ reinterpret_cast<typelib_TypeDescription **>(ppRet), typelib_TypeClass_INTERFACE_ATTRIBUTE, pTypeName );
+
+ rtl_uString_newFromStr_WithLength( &(*ppRet)->aBase.pMemberName,
+ pTypeName->buffer + nOffset +1,
+ pTypeName->length - nOffset -1 );
+ (*ppRet)->aBase.nPosition = nAbsolutePosition;
+ typelib_typedescriptionreference_new( &(*ppRet)->pAttributeTypeRef, eAttributeTypeClass, pAttributeTypeName );
+ (*ppRet)->bReadOnly = bReadOnly;
+ (*ppRet)->pInterface = pInterface;
+ (*ppRet)->pBaseRef = nullptr;
+ OSL_ASSERT(
+ (nAbsolutePosition >= pInterface->nAllMembers - pInterface->nMembers)
+ && nAbsolutePosition < pInterface->nAllMembers);
+ (*ppRet)->nIndex = nAbsolutePosition
+ - (pInterface->nAllMembers - pInterface->nMembers);
+ (*ppRet)->nGetExceptions = nGetExceptions;
+ (*ppRet)->ppGetExceptions = copyExceptions(
+ nGetExceptions, ppGetExceptionNames);
+ (*ppRet)->nSetExceptions = nSetExceptions;
+ (*ppRet)->ppSetExceptions = copyExceptions(
+ nSetExceptions, ppSetExceptionNames);
+ static_assert( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE_ATTRIBUTE ) );
+ assert(reinterpret_cast<typelib_TypeDescription *>(*ppRet)->pWeakRef == nullptr);
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_acquire(
+ typelib_TypeDescription * pTypeDescription )
+ SAL_THROW_EXTERN_C()
+{
+ osl_atomic_increment( &pTypeDescription->nRefCount );
+}
+
+
+namespace {
+
+void deleteExceptions(
+ sal_Int32 count, typelib_TypeDescriptionReference ** exceptions)
+{
+ for (sal_Int32 i = 0; i < count; ++i) {
+ typelib_typedescriptionreference_release(exceptions[i]);
+ }
+ delete[] exceptions;
+}
+
+}
+
+// frees anything except typelib_TypeDescription base!
+static void typelib_typedescription_destructExtendedMembers(
+ typelib_TypeDescription * pTD )
+{
+ OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTD->eTypeClass );
+
+ switch( pTD->eTypeClass )
+ {
+ case typelib_TypeClass_SEQUENCE:
+ if( reinterpret_cast<typelib_IndirectTypeDescription*>(pTD)->pType )
+ typelib_typedescriptionreference_release( reinterpret_cast<typelib_IndirectTypeDescription*>(pTD)->pType );
+ break;
+ case typelib_TypeClass_STRUCT:
+ delete[] reinterpret_cast< typelib_StructTypeDescription * >(pTD)->
+ pParameterizedTypes;
+ [[fallthrough]];
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_CompoundTypeDescription * pCTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD);
+ if( pCTD->pBaseTypeDescription )
+ typelib_typedescription_release( &pCTD->pBaseTypeDescription->aBase );
+ sal_Int32 i;
+ for( i = 0; i < pCTD->nMembers; i++ )
+ {
+ typelib_typedescriptionreference_release( pCTD->ppTypeRefs[i] );
+ }
+ if (pCTD->ppMemberNames)
+ {
+ for ( i = 0; i < pCTD->nMembers; i++ )
+ {
+ rtl_uString_release( pCTD->ppMemberNames[i] );
+ }
+ delete [] pCTD->ppMemberNames;
+ }
+ delete [] pCTD->ppTypeRefs;
+ delete [] pCTD->pMemberOffsets;
+ }
+ break;
+ case typelib_TypeClass_INTERFACE:
+ {
+ typelib_InterfaceTypeDescription * pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD);
+ for( sal_Int32 i = 0; i < pITD->nAllMembers; i++ )
+ {
+ typelib_typedescriptionreference_release( pITD->ppAllMembers[i] );
+ }
+ delete [] pITD->ppAllMembers;
+ delete [] pITD->pMapMemberIndexToFunctionIndex;
+ delete [] pITD->pMapFunctionIndexToMemberIndex;
+ for (sal_Int32 i = 0; i < pITD->nBaseTypes; ++i) {
+ typelib_typedescription_release(
+ reinterpret_cast< typelib_TypeDescription * >(
+ pITD->ppBaseTypes[i]));
+ }
+ delete[] pITD->ppBaseTypes;
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription * pIMTD = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(pTD);
+ if( pIMTD->pReturnTypeRef )
+ typelib_typedescriptionreference_release( pIMTD->pReturnTypeRef );
+ for( sal_Int32 i = 0; i < pIMTD->nParams; i++ )
+ {
+ rtl_uString_release( pIMTD->pParams[ i ].pName );
+ typelib_typedescriptionreference_release( pIMTD->pParams[ i ].pTypeRef );
+ }
+ delete [] pIMTD->pParams;
+ deleteExceptions(pIMTD->nExceptions, pIMTD->ppExceptions);
+ rtl_uString_release( pIMTD->aBase.pMemberName );
+ typelib_typedescription_release(&pIMTD->pInterface->aBase);
+ if (pIMTD->pBaseRef != nullptr) {
+ typelib_typedescriptionreference_release(pIMTD->pBaseRef);
+ }
+ }
+ break;
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription * pIATD = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pTD);
+ deleteExceptions(pIATD->nGetExceptions, pIATD->ppGetExceptions);
+ deleteExceptions(pIATD->nSetExceptions, pIATD->ppSetExceptions);
+ if( pIATD->pAttributeTypeRef )
+ typelib_typedescriptionreference_release( pIATD->pAttributeTypeRef );
+ if( pIATD->aBase.pMemberName )
+ rtl_uString_release( pIATD->aBase.pMemberName );
+ typelib_typedescription_release(&pIATD->pInterface->aBase);
+ if (pIATD->pBaseRef != nullptr) {
+ typelib_typedescriptionreference_release(pIATD->pBaseRef);
+ }
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ {
+ typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(pTD);
+ for ( sal_Int32 nPos = pEnum->nEnumValues; nPos--; )
+ {
+ rtl_uString_release( pEnum->ppEnumNames[nPos] );
+ }
+ delete [] pEnum->ppEnumNames;
+ delete [] pEnum->pEnumValues;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_release(
+ typelib_TypeDescription * pTD )
+ SAL_THROW_EXTERN_C()
+{
+ sal_Int32 ref = osl_atomic_decrement( &pTD->nRefCount );
+ OSL_ASSERT(ref >= 0);
+ if (0 != ref)
+ return;
+
+ TypeDescriptor_Init_Impl &rInit = Init();
+ if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pTD->eTypeClass ) )
+ {
+ if( pTD->pWeakRef )
+ {
+ {
+ MutexGuard aGuard( rInit.maMutex );
+ // remove this description from the weak reference
+ pTD->pWeakRef->pType = nullptr;
+ }
+ typelib_typedescriptionreference_release( pTD->pWeakRef );
+ }
+ }
+ else
+ {
+ // this description is a reference too, so remove it from the hash table
+ MutexGuard aGuard( rInit.maMutex );
+ WeakMap_Impl::iterator aIt = rInit.maWeakMap.find( pTD->pTypeName->buffer );
+ if( aIt != rInit.maWeakMap.end() && static_cast<void *>((*aIt).second) == static_cast<void *>(pTD) )
+ {
+ // remove only if it contains the same object
+ rInit.maWeakMap.erase( aIt );
+ }
+ }
+
+ typelib_typedescription_destructExtendedMembers( pTD );
+ rtl_uString_release( pTD->pTypeName );
+
+#if OSL_DEBUG_LEVEL > 0
+ switch( pTD->eTypeClass )
+ {
+ case typelib_TypeClass_SEQUENCE:
+ osl_atomic_decrement( &rInit.nIndirectTypeDescriptionCount );
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ osl_atomic_decrement( &rInit.nCompoundTypeDescriptionCount );
+ break;
+ case typelib_TypeClass_INTERFACE:
+ osl_atomic_decrement( &rInit.nInterfaceTypeDescriptionCount );
+ break;
+ case typelib_TypeClass_INTERFACE_METHOD:
+ osl_atomic_decrement( &rInit.nInterfaceMethodTypeDescriptionCount );
+ break;
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ osl_atomic_decrement( &rInit.nInterfaceAttributeTypeDescriptionCount );
+ break;
+ case typelib_TypeClass_ENUM:
+ osl_atomic_decrement( &rInit.nEnumTypeDescriptionCount );
+ break;
+ default:
+ osl_atomic_decrement( &rInit.nTypeDescriptionCount );
+ }
+#endif
+
+ freeTypeDescription(pTD);
+}
+
+
+extern "C" void SAL_CALL typelib_typedescription_register(
+ typelib_TypeDescription ** ppNewDescription )
+ SAL_THROW_EXTERN_C()
+{
+ // connect the description with the weak reference
+ TypeDescriptor_Init_Impl &rInit = Init();
+ ClearableMutexGuard aGuard( rInit.maMutex );
+
+ typelib_TypeDescriptionReference * pTDR = nullptr;
+ typelib_typedescriptionreference_getByName( &pTDR, (*ppNewDescription)->pTypeName );
+
+ OSL_ASSERT( (*ppNewDescription)->pWeakRef || TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppNewDescription)->eTypeClass ) );
+ if( pTDR )
+ {
+ OSL_ASSERT( (*ppNewDescription)->eTypeClass == pTDR->eTypeClass );
+ if( pTDR->pType )
+ {
+ if (TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pTDR->eTypeClass ))
+ {
+ // pRef->pType->pWeakRef == 0 means that the description is empty
+ if (pTDR->pType->pWeakRef)
+ {
+ if (osl_atomic_increment( &pTDR->pType->nRefCount ) > 1)
+ {
+ // The reference is incremented. The object cannot be destroyed.
+ // Release the guard at the earliest point.
+ aGuard.clear();
+ ::typelib_typedescription_release( *ppNewDescription );
+ *ppNewDescription = pTDR->pType;
+ ::typelib_typedescriptionreference_release( pTDR );
+ return;
+ }
+ // destruction of this type in progress (another thread!)
+ (void)osl_atomic_decrement( &pTDR->pType->nRefCount );
+ }
+ // take new descr
+ pTDR->pType = *ppNewDescription;
+ OSL_ASSERT( ! (*ppNewDescription)->pWeakRef );
+ (*ppNewDescription)->pWeakRef = pTDR;
+ return;
+ }
+ // !reallyWeak
+
+ if ((static_cast<void *>(pTDR) != static_cast<void *>(*ppNewDescription)) && // if different
+ (!pTDR->pType->pWeakRef || // uninit: ref data only set
+ // new one is complete:
+ (!pTDR->pType->bComplete && (*ppNewDescription)->bComplete) ||
+ // new one may be partly initialized interface (except of tables):
+ (typelib_TypeClass_INTERFACE == pTDR->pType->eTypeClass &&
+ !reinterpret_cast<typelib_InterfaceTypeDescription *>(pTDR->pType)->ppAllMembers &&
+ (*reinterpret_cast<typelib_InterfaceTypeDescription **>(ppNewDescription))->ppAllMembers)))
+ {
+ // uninitialized or incomplete
+
+ if (pTDR->pType->pWeakRef) // if init
+ {
+ switch (pTDR->pType->eTypeClass) {
+ case typelib_TypeClass_ENUM:
+ {
+ auto const src = reinterpret_cast<typelib_EnumTypeDescription *>(
+ *ppNewDescription);
+ auto const dst = reinterpret_cast<typelib_EnumTypeDescription *>(
+ pTDR->pType);
+ assert(dst->nEnumValues == 0);
+ assert(dst->ppEnumNames == nullptr);
+ assert(dst->pEnumValues == nullptr);
+ std::swap(src->nEnumValues, dst->nEnumValues);
+ std::swap(src->ppEnumNames, dst->ppEnumNames);
+ std::swap(src->pEnumValues, dst->pEnumValues);
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ auto const src = reinterpret_cast<typelib_CompoundTypeDescription *>(
+ *ppNewDescription);
+ auto const dst = reinterpret_cast<typelib_CompoundTypeDescription *>(
+ pTDR->pType);
+ assert(
+ (dst->pBaseTypeDescription == nullptr)
+ == (src->pBaseTypeDescription == nullptr));
+ assert(dst->nMembers == src->nMembers);
+ assert((dst->pMemberOffsets == nullptr) == (dst->nMembers == 0));
+ assert((dst->ppTypeRefs == nullptr) == (dst->nMembers == 0));
+ assert(dst->ppMemberNames == nullptr);
+ assert(
+ pTDR->pType->eTypeClass != typelib_TypeClass_STRUCT
+ || ((reinterpret_cast<typelib_StructTypeDescription *>(
+ dst)->pParameterizedTypes
+ == nullptr)
+ == (reinterpret_cast<typelib_StructTypeDescription *>(
+ src)->pParameterizedTypes
+ == nullptr)));
+ std::swap(src->ppMemberNames, dst->ppMemberNames);
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ auto const src = reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ *ppNewDescription);
+ auto const dst = reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ pTDR->pType);
+ assert(
+ (dst->pBaseTypeDescription == nullptr)
+ == (src->pBaseTypeDescription == nullptr));
+ assert(dst->nMembers == 0);
+ assert(dst->ppMembers == nullptr);
+ assert(dst->nAllMembers == 0);
+ assert(dst->ppAllMembers == nullptr);
+ assert(dst->pMapMemberIndexToFunctionIndex == nullptr);
+ assert(dst->nMapFunctionIndexToMemberIndex == 0);
+ assert(dst->pMapFunctionIndexToMemberIndex == nullptr);
+ assert(dst->nBaseTypes == src->nBaseTypes);
+ assert((dst->ppBaseTypes == nullptr) == (src->ppBaseTypes == nullptr));
+ std::swap(src->nMembers, dst->nMembers);
+ std::swap(src->ppMembers, dst->ppMembers);
+ std::swap(src->nAllMembers, dst->nAllMembers);
+ std::swap(src->ppAllMembers, dst->ppAllMembers);
+ std::swap(
+ src->pMapMemberIndexToFunctionIndex,
+ dst->pMapMemberIndexToFunctionIndex);
+ std::swap(
+ src->nMapFunctionIndexToMemberIndex,
+ dst->nMapFunctionIndexToMemberIndex);
+ std::swap(
+ src->pMapFunctionIndexToMemberIndex,
+ dst->pMapFunctionIndexToMemberIndex);
+ break;
+ }
+ default:
+ assert(false); // this cannot happen
+ }
+ }
+ else
+ {
+ // pTDR->pType->pWeakRef == 0 means that the description is empty
+ // description is not weak and the not the same
+ sal_Int32 nSize = getDescriptionSize( (*ppNewDescription)->eTypeClass );
+
+ // copy all specific data for the descriptions
+ memcpy(
+ pTDR->pType +1,
+ *ppNewDescription +1,
+ nSize - sizeof(typelib_TypeDescription) );
+
+ memset(
+ *ppNewDescription +1,
+ 0,
+ nSize - sizeof( typelib_TypeDescription ) );
+ }
+
+ pTDR->pType->bComplete = (*ppNewDescription)->bComplete;
+ pTDR->pType->nSize = (*ppNewDescription)->nSize;
+ pTDR->pType->nAlignment = (*ppNewDescription)->nAlignment;
+
+ if( pTDR->pType->bOnDemand && !(*ppNewDescription)->bOnDemand )
+ {
+ // switch from OnDemand to !OnDemand, so the description must be acquired
+ typelib_typedescription_acquire( pTDR->pType );
+ }
+ else if( !pTDR->pType->bOnDemand && (*ppNewDescription)->bOnDemand )
+ {
+ // switch from !OnDemand to OnDemand, so the description must be released
+ assert(pTDR->pType->nRefCount > 1);
+ // coverity[freed_arg] - pType's nRefCount is > 1 here
+ typelib_typedescription_release( pTDR->pType );
+ }
+
+ pTDR->pType->bOnDemand = (*ppNewDescription)->bOnDemand;
+ // initialized
+ pTDR->pType->pWeakRef = pTDR;
+ }
+
+ typelib_typedescription_release( *ppNewDescription );
+ // pTDR was acquired by getByName(), so it must not be acquired again
+ *ppNewDescription = pTDR->pType;
+ return;
+ }
+ }
+ else if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppNewDescription)->eTypeClass) )
+ {
+ typelib_typedescriptionreference_new(
+ &pTDR, (*ppNewDescription)->eTypeClass, (*ppNewDescription)->pTypeName );
+ }
+ else
+ {
+ pTDR = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppNewDescription);
+
+ // description is the weak itself, so register it
+ rInit.maWeakMap[pTDR->pTypeName->buffer] = pTDR;
+ OSL_ASSERT( static_cast<void *>(*ppNewDescription) == static_cast<void *>(pTDR) );
+ }
+
+ // By default this reference is not really weak. The reference hold the description
+ // and the description hold the reference.
+ if( !(*ppNewDescription)->bOnDemand )
+ {
+ // nor OnDemand so the description must be acquired if registered
+ typelib_typedescription_acquire( *ppNewDescription );
+ }
+
+ pTDR->pType = *ppNewDescription;
+ (*ppNewDescription)->pWeakRef = pTDR;
+ OSL_ASSERT( rtl_ustr_compare( pTDR->pTypeName->buffer, (*ppNewDescription)->pTypeName->buffer ) == 0 );
+ OSL_ASSERT( pTDR->eTypeClass == (*ppNewDescription)->eTypeClass );
+}
+
+
+static bool type_equals(
+ typelib_TypeDescriptionReference const * p1, typelib_TypeDescriptionReference const * p2 )
+{
+ return (p1 == p2 ||
+ (p1->eTypeClass == p2->eTypeClass &&
+ p1->pTypeName->length == p2->pTypeName->length &&
+ rtl_ustr_compare( p1->pTypeName->buffer, p2->pTypeName->buffer ) == 0));
+}
+extern "C" sal_Bool SAL_CALL typelib_typedescription_equals(
+ const typelib_TypeDescription * p1, const typelib_TypeDescription * p2 )
+ SAL_THROW_EXTERN_C()
+{
+ return type_equals(
+ reinterpret_cast<typelib_TypeDescriptionReference const *>(p1), reinterpret_cast<typelib_TypeDescriptionReference const *>(p2) );
+}
+
+
+extern "C" sal_Int32 typelib_typedescription_getAlignedUnoSize(
+ const typelib_TypeDescription * pTypeDescription,
+ sal_Int32 nOffset, sal_Int32 & rMaxIntegralTypeSize )
+ SAL_THROW_EXTERN_C()
+{
+ sal_Int32 nSize;
+ if( pTypeDescription->nSize )
+ {
+ // size and alignment are set
+ rMaxIntegralTypeSize = pTypeDescription->nAlignment;
+ nSize = pTypeDescription->nSize;
+ }
+ else
+ {
+ nSize = 0;
+ rMaxIntegralTypeSize = 1;
+
+ OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTypeDescription->eTypeClass );
+
+ switch( pTypeDescription->eTypeClass )
+ {
+ case typelib_TypeClass_INTERFACE:
+ // FEATURE_INTERFACE
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( void * ));
+ break;
+ case typelib_TypeClass_ENUM:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( typelib_TypeClass ));
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ // FEATURE_EMPTYCLASS
+ {
+ typelib_CompoundTypeDescription const * pTmp = reinterpret_cast<typelib_CompoundTypeDescription const *>(pTypeDescription);
+ sal_Int32 nStructSize = 0;
+ if( pTmp->pBaseTypeDescription )
+ {
+ // inherit structs extends the base struct.
+ nStructSize = pTmp->pBaseTypeDescription->aBase.nSize;
+ rMaxIntegralTypeSize = pTmp->pBaseTypeDescription->aBase.nAlignment;
+ }
+ for( sal_Int32 i = 0; i < pTmp->nMembers; i++ )
+ {
+ typelib_TypeDescription * pMemberType = nullptr;
+ typelib_TypeDescriptionReference * pMemberRef = pTmp->ppTypeRefs[i];
+
+ sal_Int32 nMaxIntegral;
+ if (pMemberRef->eTypeClass == typelib_TypeClass_INTERFACE
+ || pMemberRef->eTypeClass == typelib_TypeClass_SEQUENCE)
+ {
+ nMaxIntegral = sal_Int32(sizeof(void *));
+ nStructSize = newAlignedSize( nStructSize, nMaxIntegral, nMaxIntegral );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pMemberType, pMemberRef );
+ nStructSize = typelib_typedescription_getAlignedUnoSize(
+ pMemberType, nStructSize, nMaxIntegral );
+ TYPELIB_DANGER_RELEASE( pMemberType );
+ }
+ if( nMaxIntegral > rMaxIntegralTypeSize )
+ rMaxIntegralTypeSize = nMaxIntegral;
+ }
+#ifdef __m68k__
+ // Anything that is at least 16 bits wide is aligned on a 16-bit
+ // boundary on the m68k default abi
+ sal_Int32 nMaxAlign = std::min(rMaxIntegralTypeSize, sal_Int32( 2 ));
+ nStructSize = (nStructSize + nMaxAlign -1) / nMaxAlign * nMaxAlign;
+#else
+ // Example: A { double; int; } structure has a size of 16 instead of 10. The
+ // compiler must follow this rule if it is possible to access members in arrays through:
+ // (Element *)((char *)pArray + sizeof( Element ) * ElementPos)
+ nStructSize = (nStructSize + rMaxIntegralTypeSize -1)
+ / rMaxIntegralTypeSize * rMaxIntegralTypeSize;
+#endif
+ nSize += nStructSize;
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( void * ));
+ break;
+ case typelib_TypeClass_ANY:
+ // FEATURE_ANY
+ nSize = sal_Int32(sizeof( uno_Any ));
+ rMaxIntegralTypeSize = sal_Int32(sizeof( void * ));
+ break;
+ case typelib_TypeClass_TYPE:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( typelib_TypeDescriptionReference * ));
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Bool ));
+ break;
+ case typelib_TypeClass_CHAR:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Unicode ));
+ break;
+ case typelib_TypeClass_STRING:
+ // FEATURE_STRING
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( rtl_uString * ));
+ break;
+ case typelib_TypeClass_FLOAT:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( float ));
+ break;
+ case typelib_TypeClass_DOUBLE:
+#ifdef AIX
+ //See previous AIX ifdef comment for an explanation
+ nSize = (sal_Int32)(sizeof(double));
+ rMaxIntegralTypeSize = (sal_Int32)(sizeof(void*));
+#else
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( double ));
+#endif
+ break;
+ case typelib_TypeClass_BYTE:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int8 ));
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int16 ));
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int32 ));
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int64 ));
+ break;
+ case typelib_TypeClass_UNKNOWN:
+ case typelib_TypeClass_SERVICE:
+ case typelib_TypeClass_MODULE:
+ default:
+ OSL_FAIL( "not convertible type" );
+ };
+ }
+
+ return newAlignedSize( nOffset, nSize, rMaxIntegralTypeSize );
+}
+
+
+namespace {
+
+typelib_TypeDescriptionReference ** copyExceptions(
+ sal_Int32 count, typelib_TypeDescriptionReference ** source)
+{
+ typelib_TypeDescriptionReference ** p
+ = new typelib_TypeDescriptionReference *[count];
+ for (sal_Int32 i = 0; i < count; ++i) {
+ p[i] = source[i];
+ typelib_typedescriptionreference_acquire(p[i]);
+ }
+ return p;
+}
+
+bool createDerivedInterfaceMemberDescription(
+ typelib_TypeDescription ** result, OUString const & name,
+ typelib_TypeDescriptionReference * baseRef,
+ typelib_TypeDescription const * base, typelib_TypeDescription * interface,
+ sal_Int32 index, sal_Int32 position)
+{
+ if (!baseRef || !base || !interface)
+ return false;
+
+ switch (base->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_typedescription_newEmpty(
+ result, typelib_TypeClass_INTERFACE_METHOD, name.pData);
+ typelib_InterfaceMethodTypeDescription const * baseMethod
+ = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const * >(base);
+ typelib_InterfaceMethodTypeDescription * newMethod
+ = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription * >(*result);
+ newMethod->aBase.nPosition = position;
+ newMethod->aBase.pMemberName
+ = baseMethod->aBase.pMemberName;
+ rtl_uString_acquire(
+ newMethod->aBase.pMemberName);
+ newMethod->pReturnTypeRef = baseMethod->pReturnTypeRef;
+ typelib_typedescriptionreference_acquire(
+ newMethod->pReturnTypeRef);
+ newMethod->nParams = baseMethod->nParams;
+ newMethod->pParams = new typelib_MethodParameter[
+ newMethod->nParams];
+ for (sal_Int32 i = 0; i < newMethod->nParams; ++i) {
+ newMethod->pParams[i].pName
+ = baseMethod->pParams[i].pName;
+ rtl_uString_acquire(
+ newMethod->pParams[i].pName);
+ newMethod->pParams[i].pTypeRef
+ = baseMethod->pParams[i].pTypeRef;
+ typelib_typedescriptionreference_acquire(
+ newMethod->pParams[i].pTypeRef);
+ newMethod->pParams[i].bIn = baseMethod->pParams[i].bIn;
+ newMethod->pParams[i].bOut = baseMethod->pParams[i].bOut;
+ }
+ newMethod->nExceptions = baseMethod->nExceptions;
+ newMethod->ppExceptions = copyExceptions(
+ baseMethod->nExceptions, baseMethod->ppExceptions);
+ newMethod->bOneWay = baseMethod->bOneWay;
+ newMethod->pInterface
+ = reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ interface);
+ newMethod->pBaseRef = baseRef;
+ newMethod->nIndex = index;
+ return true;
+ }
+
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_typedescription_newEmpty(
+ result, typelib_TypeClass_INTERFACE_ATTRIBUTE, name.pData);
+ typelib_InterfaceAttributeTypeDescription const * baseAttribute
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const * >(base);
+ typelib_InterfaceAttributeTypeDescription * newAttribute
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription * >(*result);
+ newAttribute->aBase.nPosition = position;
+ newAttribute->aBase.pMemberName
+ = baseAttribute->aBase.pMemberName;
+ rtl_uString_acquire(newAttribute->aBase.pMemberName);
+ newAttribute->bReadOnly = baseAttribute->bReadOnly;
+ newAttribute->pAttributeTypeRef
+ = baseAttribute->pAttributeTypeRef;
+ typelib_typedescriptionreference_acquire(newAttribute->pAttributeTypeRef);
+ newAttribute->pInterface
+ = reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ interface);
+ newAttribute->pBaseRef = baseRef;
+ newAttribute->nIndex = index;
+ newAttribute->nGetExceptions = baseAttribute->nGetExceptions;
+ newAttribute->ppGetExceptions = copyExceptions(
+ baseAttribute->nGetExceptions,
+ baseAttribute->ppGetExceptions);
+ newAttribute->nSetExceptions = baseAttribute->nSetExceptions;
+ newAttribute->ppSetExceptions = copyExceptions(
+ baseAttribute->nSetExceptions,
+ baseAttribute->ppSetExceptions);
+ return true;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+}
+
+extern "C" void SAL_CALL typelib_typedescription_getByName(
+ typelib_TypeDescription ** ppRet, rtl_uString * pName )
+ SAL_THROW_EXTERN_C()
+{
+ if( *ppRet )
+ {
+ typelib_typedescription_release( *ppRet );
+ *ppRet = nullptr;
+ }
+
+ static bool bInited = false;
+ TypeDescriptor_Init_Impl &rInit = Init();
+
+ if( !bInited )
+ {
+ // guard against multi thread access
+ MutexGuard aGuard( rInit.maMutex );
+ if( !bInited )
+ {
+ // avoid recursion during the next ...new calls
+ bInited = true;
+
+ typelib_TypeDescription * pType = nullptr;
+ typelib_typedescription_new( &pType, typelib_TypeClass_TYPE, OUString("type").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_VOID, OUString("void").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_BOOLEAN, OUString("boolean").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_CHAR, OUString("char").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_BYTE, OUString("byte").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_STRING, OUString("string").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_SHORT, OUString("short").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_SHORT, OUString("unsigned short").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_LONG, OUString("long").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_LONG, OUString("unsigned long").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_HYPER, OUString("hyper").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_HYPER, OUString("unsigned hyper").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_FLOAT, OUString("float").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_DOUBLE, OUString("double").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_new( &pType, typelib_TypeClass_ANY, OUString("any").pData, nullptr, 0, nullptr );
+ typelib_typedescription_register( &pType );
+ typelib_typedescription_release( pType );
+ }
+ }
+
+ typelib_TypeDescriptionReference * pTDR = nullptr;
+ typelib_typedescriptionreference_getByName( &pTDR, pName );
+ if( pTDR )
+ {
+ {
+ // guard against multi thread access
+ MutexGuard aGuard( rInit.maMutex );
+ // pTDR->pType->pWeakRef == 0 means that the description is empty
+ if( pTDR->pType && pTDR->pType->pWeakRef )
+ {
+ typelib_typedescription_acquire( pTDR->pType );
+ *ppRet = pTDR->pType;
+ }
+ }
+ typelib_typedescriptionreference_release( pTDR );
+ }
+
+ if (nullptr != *ppRet)
+ return;
+
+ // check for sequence
+ OUString const & name = OUString::unacquired( &pName );
+ if (2 < name.getLength() && '[' == name[ 0 ])
+ {
+ OUString element_name( name.copy( 2 ) );
+ typelib_TypeDescription * element_td = nullptr;
+ typelib_typedescription_getByName( &element_td, element_name.pData );
+ if (nullptr != element_td)
+ {
+ typelib_typedescription_new(
+ ppRet, typelib_TypeClass_SEQUENCE, pName, element_td->pWeakRef, 0, nullptr );
+ // register?
+ typelib_typedescription_release( element_td );
+ }
+ }
+ if (nullptr == *ppRet)
+ {
+ // Check for derived interface member type:
+ sal_Int32 i1 = name.lastIndexOf(":@");
+ if (i1 >= 0) {
+ sal_Int32 i2 = i1 + RTL_CONSTASCII_LENGTH(":@");
+ sal_Int32 i3 = name.indexOf(',', i2);
+ if (i3 >= 0) {
+ sal_Int32 i4 = name.indexOf(':', i3);
+ if (i4 >= 0) {
+ typelib_TypeDescriptionReference * pBaseRef = nullptr;
+ typelib_TypeDescription * pBase = nullptr;
+ typelib_TypeDescription * pInterface = nullptr;
+ typelib_typedescriptionreference_getByName(
+ &pBaseRef, name.copy(0, i1).pData);
+ if (pBaseRef != nullptr) {
+ typelib_typedescriptionreference_getDescription(
+ &pBase, pBaseRef);
+ }
+ typelib_typedescription_getByName(
+ &pInterface, name.copy(i4 + 1).pData);
+ if (!createDerivedInterfaceMemberDescription(
+ ppRet, name, pBaseRef, pBase, pInterface,
+ o3tl::toInt32(name.subView(i2, i3 - i2)),
+ o3tl::toInt32(name.subView(i3 + 1, i4 - i3 - 1))))
+ {
+ if (pInterface != nullptr) {
+ typelib_typedescription_release(pInterface);
+ }
+ if (pBase != nullptr) {
+ typelib_typedescription_release(pBase);
+ }
+ if (pBaseRef != nullptr) {
+ typelib_typedescriptionreference_release(
+ pBaseRef);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (nullptr == *ppRet)
+ {
+ // on demand access
+ rInit.callChain( ppRet, pName );
+ }
+
+ if( !(*ppRet) )
+ return;
+
+ // typedescription found
+ if (typelib_TypeClass_TYPEDEF == (*ppRet)->eTypeClass)
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(*ppRet)->pType );
+ typelib_typedescription_release( *ppRet );
+ *ppRet = pTD;
+ }
+ else
+ {
+ // set to on demand
+ (*ppRet)->bOnDemand = true;
+ // The type description is hold by the reference until
+ // on demand is activated.
+ typelib_typedescription_register( ppRet );
+
+ // insert into the cache
+ MutexGuard aGuard( rInit.maMutex );
+ if( rInit.maCache.size() >= nCacheSize )
+ {
+ typelib_typedescription_release( rInit.maCache.front() );
+ rInit.maCache.pop_front();
+ }
+ // descriptions in the cache must be acquired!
+ typelib_typedescription_acquire( *ppRet );
+ rInit.maCache.push_back( *ppRet );
+ }
+}
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_newByAsciiName(
+ typelib_TypeDescriptionReference ** ppTDR,
+ typelib_TypeClass eTypeClass,
+ const char * pTypeName )
+ SAL_THROW_EXTERN_C()
+{
+ OUString aTypeName( OUString::createFromAscii( pTypeName ) );
+ typelib_typedescriptionreference_new( ppTDR, eTypeClass, aTypeName.pData );
+}
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_new(
+ typelib_TypeDescriptionReference ** ppTDR,
+ typelib_TypeClass eTypeClass, rtl_uString * pTypeName )
+ SAL_THROW_EXTERN_C()
+{
+ TypeDescriptor_Init_Impl &rInit = Init();
+ if( eTypeClass == typelib_TypeClass_TYPEDEF )
+ {
+ // on demand access
+ typelib_TypeDescription * pRet = nullptr;
+ rInit.callChain( &pRet, pTypeName );
+ if( pRet )
+ {
+ // typedescription found
+ if (typelib_TypeClass_TYPEDEF == pRet->eTypeClass)
+ {
+ typelib_typedescriptionreference_acquire(
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pRet)->pType );
+ if (*ppTDR)
+ typelib_typedescriptionreference_release( *ppTDR );
+ *ppTDR = reinterpret_cast<typelib_IndirectTypeDescription *>(pRet)->pType;
+ typelib_typedescription_release( pRet );
+ }
+ else
+ {
+ // set to on demand
+ pRet->bOnDemand = true;
+ // The type description is hold by the reference until
+ // on demand is activated.
+ typelib_typedescription_register( &pRet );
+
+ // insert into the cache
+ MutexGuard aGuard( rInit.maMutex );
+ if( rInit.maCache.size() >= nCacheSize )
+ {
+ typelib_typedescription_release( rInit.maCache.front() );
+ rInit.maCache.pop_front();
+ }
+ rInit.maCache.push_back( pRet );
+ // pRet kept acquired for cache
+
+ typelib_typedescriptionreference_acquire( pRet->pWeakRef );
+ if (*ppTDR)
+ typelib_typedescriptionreference_release( *ppTDR );
+ *ppTDR = pRet->pWeakRef;
+ }
+ }
+ else if (*ppTDR)
+ {
+ SAL_INFO("cppu.typelib", "typedef not found : " << pTypeName);
+ typelib_typedescriptionreference_release( *ppTDR );
+ *ppTDR = nullptr;
+ }
+ return;
+ }
+
+ MutexGuard aGuard( rInit.maMutex );
+ typelib_typedescriptionreference_getByName( ppTDR, pTypeName );
+ if( *ppTDR )
+ return;
+
+ if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( eTypeClass ) )
+ {
+ typelib_TypeDescriptionReference * pTDR = new typelib_TypeDescriptionReference;
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_increment( &rInit.nTypeDescriptionReferenceCount );
+#endif
+ pTDR->nRefCount = 1;
+ pTDR->nStaticRefCount = 0;
+ pTDR->eTypeClass = eTypeClass;
+ pTDR->pUniqueIdentifier = nullptr;
+ pTDR->pReserved = nullptr;
+ pTDR->pTypeName = pTypeName;
+ rtl_uString_acquire( pTDR->pTypeName );
+ pTDR->pType = nullptr;
+ *ppTDR = pTDR;
+ }
+ else
+ {
+ typelib_typedescription_newEmpty( reinterpret_cast<typelib_TypeDescription ** >(ppTDR), eTypeClass, pTypeName );
+ // description will be registered but not acquired
+ (*reinterpret_cast<typelib_TypeDescription **>(ppTDR))->bOnDemand = true;
+ (*reinterpret_cast<typelib_TypeDescription **>(ppTDR))->bComplete = false;
+ }
+
+ // Heavy hack, the const sal_Unicode * is hold by the typedescription reference
+ // not registered
+ rInit.maWeakMap[ (*ppTDR)->pTypeName->buffer ] = *ppTDR;
+}
+
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_acquire(
+ typelib_TypeDescriptionReference * pRef )
+ SAL_THROW_EXTERN_C()
+{
+ osl_atomic_increment( &pRef->nRefCount );
+}
+
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_release(
+ typelib_TypeDescriptionReference * pRef )
+ SAL_THROW_EXTERN_C()
+{
+ // Is it a type description?
+ if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pRef->eTypeClass ) )
+ {
+ if( ! osl_atomic_decrement( &pRef->nRefCount ) )
+ {
+ TypeDescriptor_Init_Impl &rInit = Init();
+ MutexGuard aGuard( rInit.maMutex );
+ WeakMap_Impl::iterator aIt = rInit.maWeakMap.find( pRef->pTypeName->buffer );
+ if( aIt != rInit.maWeakMap.end() && (*aIt).second == pRef )
+ {
+ // remove only if it contains the same object
+ rInit.maWeakMap.erase( aIt );
+ }
+
+ rtl_uString_release( pRef->pTypeName );
+ OSL_ASSERT( pRef->pType == nullptr );
+#if OSL_DEBUG_LEVEL > 0
+ osl_atomic_decrement( &rInit.nTypeDescriptionReferenceCount );
+#endif
+ delete pRef;
+ }
+ }
+ else
+ {
+ typelib_typedescription_release( reinterpret_cast<typelib_TypeDescription *>(pRef) );
+ }
+}
+
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_getDescription(
+ typelib_TypeDescription ** ppRet, typelib_TypeDescriptionReference * pRef )
+ SAL_THROW_EXTERN_C()
+{
+ if( *ppRet )
+ {
+ typelib_typedescription_release( *ppRet );
+ *ppRet = nullptr;
+ }
+
+ if( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pRef->eTypeClass ) && pRef->pType && pRef->pType->pWeakRef )
+ {
+ // reference is a description and initialized
+ osl_atomic_increment( &reinterpret_cast<typelib_TypeDescription *>(pRef)->nRefCount );
+ *ppRet = reinterpret_cast<typelib_TypeDescription *>(pRef);
+ return;
+ }
+
+ {
+ MutexGuard aGuard( Init().maMutex );
+ // pRef->pType->pWeakRef == 0 means that the description is empty
+ if( pRef->pType && pRef->pType->pWeakRef )
+ {
+ sal_Int32 n = osl_atomic_increment( &pRef->pType->nRefCount );
+ if( n > 1 )
+ {
+ // The reference is incremented. The object cannot be destroyed.
+ // Release the guard at the earliest point.
+ *ppRet = pRef->pType;
+ return;
+ }
+ (void)osl_atomic_decrement( &pRef->pType->nRefCount );
+ // destruction of this type in progress (another thread!)
+ // no access through this weak reference
+ pRef->pType = nullptr;
+ }
+ }
+
+ typelib_typedescription_getByName( ppRet, pRef->pTypeName );
+ OSL_ASSERT( !*ppRet || rtl_ustr_compare( pRef->pTypeName->buffer, (*ppRet)->pTypeName->buffer ) == 0 );
+ OSL_ASSERT( !*ppRet || pRef->eTypeClass == (*ppRet)->eTypeClass );
+ OSL_ASSERT( !*ppRet || pRef == (*ppRet)->pWeakRef );
+ pRef->pType = *ppRet;
+}
+
+
+extern "C" void typelib_typedescriptionreference_getByName(
+ typelib_TypeDescriptionReference ** ppRet, rtl_uString const * pName )
+ SAL_THROW_EXTERN_C()
+{
+ if( *ppRet )
+ {
+ typelib_typedescriptionreference_release( *ppRet );
+ *ppRet = nullptr;
+ }
+ TypeDescriptor_Init_Impl &rInit = Init();
+
+ MutexGuard aGuard( rInit.maMutex );
+ WeakMap_Impl::const_iterator aIt = rInit.maWeakMap.find( pName->buffer );
+ if( aIt == rInit.maWeakMap.end() )
+ return;
+
+ sal_Int32 n = osl_atomic_increment( &(*aIt).second->nRefCount );
+ if( n > 1 )
+ {
+ // The reference is incremented. The object cannot be destroyed.
+ // Release the guard at the earliest point.
+ *ppRet = (*aIt).second;
+ }
+ else
+ {
+ // destruction of this type in progress (another thread!)
+ // no access through this weak reference
+ (void)osl_atomic_decrement( &(*aIt).second->nRefCount );
+ }
+}
+
+
+extern "C" sal_Bool SAL_CALL typelib_typedescriptionreference_equals(
+ const typelib_TypeDescriptionReference * p1,
+ const typelib_TypeDescriptionReference * p2 )
+ SAL_THROW_EXTERN_C()
+{
+ return (p1 == p2 ||
+ (p1->eTypeClass == p2->eTypeClass &&
+ p1->pTypeName->length == p2->pTypeName->length &&
+ rtl_ustr_compare( p1->pTypeName->buffer, p2->pTypeName->buffer ) == 0));
+}
+
+
+extern "C" void SAL_CALL typelib_typedescriptionreference_assign(
+ typelib_TypeDescriptionReference ** ppDest,
+ typelib_TypeDescriptionReference * pSource )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppDest != pSource)
+ {
+ ::typelib_typedescriptionreference_acquire( pSource );
+ ::typelib_typedescriptionreference_release( *ppDest );
+ *ppDest = pSource;
+ }
+}
+
+
+extern "C" void SAL_CALL typelib_setCacheSize( sal_Int32 )
+ SAL_THROW_EXTERN_C()
+{
+}
+
+
+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, false, false, false, false, true, false },
+/* TypeClass_DOUBLE */ { false, false, true, true, true, true, true, false, false, true, true }
+};
+
+
+extern "C" sal_Bool SAL_CALL typelib_typedescriptionreference_isAssignableFrom(
+ typelib_TypeDescriptionReference * pAssignable,
+ typelib_TypeDescriptionReference * pFrom )
+ SAL_THROW_EXTERN_C()
+{
+ if (!pAssignable || !pFrom)
+ return false;
+
+ typelib_TypeClass eAssignable = pAssignable->eTypeClass;
+ typelib_TypeClass eFrom = pFrom->eTypeClass;
+
+ if (eAssignable == typelib_TypeClass_ANY) // anything can be assigned to an any .)
+ return true;
+ if (eAssignable == eFrom)
+ {
+ if (type_equals( pAssignable, pFrom )) // first shot
+ {
+ return true;
+ }
+ switch (eAssignable)
+ {
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pFromDescr = nullptr;
+ TYPELIB_DANGER_GET( &pFromDescr, pFrom );
+ if (!reinterpret_cast<typelib_CompoundTypeDescription *>(pFromDescr)->pBaseTypeDescription)
+ {
+ TYPELIB_DANGER_RELEASE( pFromDescr );
+ return false;
+ }
+ bool bRet = typelib_typedescriptionreference_isAssignableFrom(
+ pAssignable,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pFromDescr)->pBaseTypeDescription->aBase.pWeakRef );
+ TYPELIB_DANGER_RELEASE( pFromDescr );
+ return bRet;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ typelib_TypeDescription * pFromDescr = nullptr;
+ TYPELIB_DANGER_GET( &pFromDescr, pFrom );
+ typelib_InterfaceTypeDescription * pFromIfc
+ = reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(pFromDescr);
+ bool bRet = false;
+ for (sal_Int32 i = 0; i < pFromIfc->nBaseTypes; ++i) {
+ if (typelib_typedescriptionreference_isAssignableFrom(
+ pAssignable,
+ pFromIfc->ppBaseTypes[i]->aBase.pWeakRef))
+ {
+ bRet = true;
+ break;
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pFromDescr );
+ return bRet;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+ }
+ return (eAssignable >= typelib_TypeClass_CHAR && eAssignable <= typelib_TypeClass_DOUBLE &&
+ eFrom >= typelib_TypeClass_CHAR && eFrom <= typelib_TypeClass_DOUBLE &&
+ s_aAssignableFromTab[eAssignable-1][eFrom-1]);
+}
+
+extern "C" sal_Bool SAL_CALL typelib_typedescription_isAssignableFrom(
+ typelib_TypeDescription * pAssignable,
+ typelib_TypeDescription * pFrom )
+ SAL_THROW_EXTERN_C()
+{
+ return typelib_typedescriptionreference_isAssignableFrom(
+ pAssignable->pWeakRef, pFrom->pWeakRef );
+}
+
+
+extern "C" sal_Bool SAL_CALL typelib_typedescription_complete(
+ typelib_TypeDescription ** ppTypeDescr )
+ SAL_THROW_EXTERN_C()
+{
+ return complete(ppTypeDescr, true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/typelib/typelib.hxx b/cppu/source/typelib/typelib.hxx
new file mode 100644
index 000000000..b62e763de
--- /dev/null
+++ b/cppu/source/typelib/typelib.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+
+extern "C" sal_Int32 typelib_typedescription_getAlignedUnoSize(
+ const typelib_TypeDescription * pTypeDescription,
+ sal_Int32 nOffset,
+ sal_Int32 & rMaxIntegralTypeSize )
+ SAL_THROW_EXTERN_C();
+
+
+extern "C" void typelib_typedescription_newEmpty(
+ typelib_TypeDescription ** ppRet,
+ typelib_TypeClass eTypeClass,
+ rtl_uString * pTypeName )
+ SAL_THROW_EXTERN_C();
+
+extern "C" void typelib_typedescriptionreference_getByName(
+ typelib_TypeDescriptionReference ** ppRet,
+ rtl_uString const * pName )
+ SAL_THROW_EXTERN_C();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/EnvDcp.cxx b/cppu/source/uno/EnvDcp.cxx
new file mode 100644
index 000000000..c5597dec4
--- /dev/null
+++ b/cppu/source/uno/EnvDcp.cxx
@@ -0,0 +1,43 @@
+/* -*- 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/EnvDcp.h>
+
+
+void uno_EnvDcp_getTypeName(rtl_uString const * pEnvDcp, rtl_uString ** ppEnvTypeName)
+{
+ sal_Int32 colIdx = rtl_ustr_indexOfChar_WithLength(pEnvDcp->buffer, pEnvDcp->length, ':');
+ if (colIdx >= 0)
+ rtl_uString_newFromStr_WithLength(ppEnvTypeName, pEnvDcp->buffer, colIdx);
+
+ else
+ rtl_uString_newFromStr(ppEnvTypeName, pEnvDcp->buffer);
+}
+
+void uno_EnvDcp_getPurpose(rtl_uString const * pEnvDcp, rtl_uString ** ppEnvPurpose)
+{
+ sal_Int32 colIdx = rtl_ustr_indexOfChar_WithLength(pEnvDcp->buffer, pEnvDcp->length, ':');
+ if (colIdx >= 0)
+ rtl_uString_newFromStr_WithLength(ppEnvPurpose, pEnvDcp->buffer + colIdx, pEnvDcp->length - colIdx);
+
+ else
+ rtl_uString_new(ppEnvPurpose);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/EnvStack.cxx b/cppu/source/uno/EnvStack.cxx
new file mode 100644
index 000000000..34fea77f4
--- /dev/null
+++ b/cppu/source/uno/EnvStack.cxx
@@ -0,0 +1,382 @@
+/* -*- 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/environment.hxx>
+#include <uno/lbnames.h>
+
+#include <cppu/EnvDcp.hxx>
+#include <cppu/Enterable.hxx>
+
+#include <osl/thread.h>
+#include <osl/thread.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <mutex>
+#include <unordered_map>
+
+using namespace com::sun::star;
+
+namespace {
+
+struct oslThreadIdentifier_equal
+{
+ bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
+};
+
+}
+
+bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
+{
+ bool result = s1 == s2;
+
+ return result;
+}
+
+namespace {
+
+struct oslThreadIdentifier_hash
+{
+ size_t operator()(oslThreadIdentifier s1) const;
+};
+
+}
+
+size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
+{
+ return s1;
+}
+
+typedef std::unordered_map<oslThreadIdentifier,
+ uno_Environment *,
+ oslThreadIdentifier_hash,
+ oslThreadIdentifier_equal> ThreadMap;
+
+namespace
+{
+ std::mutex s_threadMap_mutex;
+ ThreadMap s_threadMap;
+}
+
+static void s_setCurrent(uno_Environment * pEnv)
+{
+ oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
+
+ std::scoped_lock guard(s_threadMap_mutex);
+ if (pEnv)
+ {
+ s_threadMap[threadId] = pEnv;
+ }
+ else
+ {
+ ThreadMap::iterator iEnv = s_threadMap.find(threadId);
+ if( iEnv != s_threadMap.end())
+ s_threadMap.erase(iEnv);
+ }
+}
+
+static uno_Environment * s_getCurrent()
+{
+ uno_Environment * pEnv = nullptr;
+
+ oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
+
+ std::scoped_lock guard(s_threadMap_mutex);
+ ThreadMap::iterator iEnv = s_threadMap.find(threadId);
+ if(iEnv != s_threadMap.end())
+ pEnv = iEnv->second;
+
+ return pEnv;
+}
+
+
+extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppEnv)
+ {
+ (*ppEnv)->release(*ppEnv);
+ *ppEnv = nullptr;
+ }
+
+ OUString currPurpose;
+
+ uno_Environment * pCurrEnv = s_getCurrent();
+ if (pCurrEnv) // no environment means no purpose
+ currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
+
+ if (pTypeName && rtl_uString_getLength(pTypeName))
+ {
+ OUString envDcp = OUString::unacquired(&pTypeName) + currPurpose;
+
+ uno_getEnvironment(ppEnv, envDcp.pData, nullptr);
+ }
+ else
+ {
+ if (pCurrEnv)
+ {
+ *ppEnv = pCurrEnv;
+ (*ppEnv)->acquire(*ppEnv);
+ }
+ else
+ {
+ OUString uno_envDcp(UNO_LB_UNO);
+ uno_getEnvironment(ppEnv, uno_envDcp.pData, nullptr);
+ }
+ }
+}
+
+static OUString s_getPrefix(std::u16string_view str1, std::u16string_view str2)
+{
+ sal_Int32 nIndex1 = 0;
+ sal_Int32 nIndex2 = 0;
+ sal_Int32 sim = 0;
+
+ std::u16string_view token1;
+ std::u16string_view token2;
+
+ do
+ {
+ token1 = o3tl::getToken(str1, 0, ':', nIndex1);
+ token2 = o3tl::getToken(str2, 0, ':', nIndex2);
+
+ if (token1 == token2)
+ sim += token1.size() + 1;
+ }
+ while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2);
+
+ OUString result;
+
+ if (sim)
+ result = str1.substr(0, sim - 1);
+
+ return result;
+}
+
+static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
+{
+ int res = 0;
+
+ std::u16string_view nextPurpose;
+
+ OUString currPurpose;
+ if (pCurrEnv)
+ currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
+
+ OUString targetPurpose;
+ if (pTargetEnv)
+ targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
+
+ OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
+ if (currPurpose.getLength() > intermPurpose.getLength())
+ {
+ sal_Int32 idx = currPurpose.lastIndexOf(':');
+ nextPurpose = currPurpose.subView(0, idx);
+
+ res = -1;
+ }
+ else if (intermPurpose.getLength() < targetPurpose.getLength())
+ {
+ sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
+ if (idx == -1)
+ nextPurpose = targetPurpose;
+
+ else
+ nextPurpose = targetPurpose.subView(0, idx);
+
+ res = 1;
+ }
+
+ if (!nextPurpose.empty())
+ {
+ OUString next_envDcp = OUString::Concat(UNO_LB_UNO) + nextPurpose;
+ uno_getEnvironment(ppEnv, next_envDcp.pData, nullptr);
+ }
+ else
+ {
+ if (*ppEnv)
+ (*ppEnv)->release(*ppEnv);
+
+ *ppEnv = nullptr;
+ }
+
+ return res;
+}
+
+extern "C" { static void s_pull(va_list * pParam)
+{
+ uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
+ va_list * pXparam = va_arg(*pParam, va_list *);
+
+ pCallee(pXparam);
+}}
+
+static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
+{
+ cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
+ if (pEnterable)
+ pEnterable->callInto(s_pull, pCallee, pParam);
+
+ else
+ pCallee(pParam);
+}
+
+static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
+{
+ va_list param;
+
+ va_start(param, pCallee);
+ s_callInto_v(pEnv, pCallee, &param);
+ va_end(param);
+}
+
+static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
+{
+ cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
+ if (pEnterable)
+ pEnterable->callOut_v(pCallee, pParam);
+
+ else
+ pCallee(pParam);
+}
+
+static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
+{
+ va_list param;
+
+ va_start(param, pCallee);
+ s_callOut_v(pEnv, pCallee, &param);
+ va_end(param);
+}
+
+static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
+
+extern "C" { static void s_environment_invoke_vv(va_list * pParam)
+{
+ uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *);
+ uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *);
+ uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
+ va_list * pXparam = va_arg(*pParam, va_list *);
+
+ s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
+}}
+
+static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
+{
+ uno_Environment * pNextEnv = nullptr;
+ switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
+ {
+ case -1:
+ s_setCurrent(pNextEnv);
+ s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
+ s_setCurrent(pCurrEnv);
+ break;
+
+ case 0: {
+ uno_Environment * hld = s_getCurrent();
+ s_setCurrent(pCurrEnv);
+ pCallee(pParam);
+ s_setCurrent(hld);
+ }
+ break;
+
+ case 1:
+ s_setCurrent(pNextEnv);
+ s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
+ s_setCurrent(pCurrEnv);
+ break;
+ }
+
+ if (pNextEnv)
+ pNextEnv->release(pNextEnv);
+}
+
+extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
+ SAL_THROW_EXTERN_C()
+{
+ s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
+}
+
+extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
+ SAL_THROW_EXTERN_C()
+{
+ va_list param;
+
+ va_start(param, pCallee);
+ uno_Environment_invoke_v(pEnv, pCallee, &param);
+ va_end(param);
+}
+
+extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
+ SAL_THROW_EXTERN_C()
+{
+ uno_Environment * pNextEnv = nullptr;
+ uno_Environment * pCurrEnv = s_getCurrent();
+
+ int res;
+ while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
+ {
+ cppu::Enterable * pEnterable;
+
+ switch(res)
+ {
+ case -1:
+ pEnterable = static_cast<cppu::Enterable *>(pCurrEnv->pReserved);
+ if (pEnterable)
+ pEnterable->leave();
+ pCurrEnv->release(pCurrEnv);
+ break;
+
+ case 1:
+ pNextEnv->acquire(pNextEnv);
+ pEnterable = static_cast<cppu::Enterable *>(pNextEnv->pReserved);
+ if (pEnterable)
+ pEnterable->enter();
+ break;
+ }
+
+ s_setCurrent(pNextEnv);
+ pCurrEnv = pNextEnv;
+ }
+}
+
+int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
+ SAL_THROW_EXTERN_C()
+{
+ int result = 1;
+
+ OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
+ if (typeName == UNO_LB_UNO)
+ {
+ cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
+ if (pEnterable)
+ result = pEnterable->isValid(reinterpret_cast<OUString *>(pReason));
+ }
+ else
+ {
+ OUString envDcp = UNO_LB_UNO + cppu::EnvDcp::getPurpose(pEnv->pTypeName);
+
+ uno::Environment env(envDcp);
+
+ result = env.isValid(reinterpret_cast<OUString *>(pReason));
+ }
+
+ return result;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/IdentityMapping.cxx b/cppu/source/uno/IdentityMapping.cxx
new file mode 100644
index 000000000..32ec32c07
--- /dev/null
+++ b/cppu/source/uno/IdentityMapping.cxx
@@ -0,0 +1,105 @@
+/* -*- 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 "IdentityMapping.hxx"
+
+#include <typelib/typedescription.h>
+#include <uno/mapping.h>
+#include <uno/environment.hxx>
+#include <utility>
+
+#include <osl/interlck.h>
+
+
+using namespace ::com::sun::star;
+
+namespace {
+
+struct IdentityMapping : public uno_Mapping
+{
+ sal_Int32 m_nRef;
+ uno::Environment m_env;
+
+ explicit IdentityMapping(uno::Environment aEnv);
+};
+
+}
+
+extern "C"
+{
+
+static void s_free(uno_Mapping * pMapping)
+{
+ delete static_cast<IdentityMapping *>(pMapping);
+}
+
+static void s_acquire(uno_Mapping * pMapping)
+{
+ static OUString s_purpose;
+
+ if (1 == osl_atomic_increment(&static_cast<IdentityMapping *>(pMapping)->m_nRef))
+ {
+ uno_registerMapping(
+ &pMapping,
+ s_free,
+ static_cast<IdentityMapping *>(pMapping)->m_env.get(),
+ static_cast<IdentityMapping *>(pMapping)->m_env.get(),
+ s_purpose.pData);
+ }
+}
+
+static void s_release(uno_Mapping * pMapping)
+{
+ if (!osl_atomic_decrement(&static_cast<IdentityMapping *>(pMapping )->m_nRef))
+ uno_revokeMapping(pMapping);
+}
+
+static void s_mapInterface(uno_Mapping * pMapping,
+ void ** ppOut,
+ void * pInterface,
+ SAL_UNUSED_PARAMETER typelib_InterfaceTypeDescription * /*pInterfaceTypeDescr*/)
+{
+ *ppOut = pInterface;
+
+ if (pInterface)
+ {
+ IdentityMapping * that = static_cast<IdentityMapping *>(pMapping);
+
+ (that->m_env.get()->pExtEnv->acquireInterface)(that->m_env.get()->pExtEnv, pInterface);
+ }
+}
+}
+
+
+IdentityMapping::IdentityMapping(uno::Environment aEnv)
+ : m_nRef(0),
+ m_env(std::move(aEnv))
+{
+ uno_Mapping::acquire = s_acquire;
+ uno_Mapping::release = s_release;
+ uno_Mapping::mapInterface = s_mapInterface;
+}
+
+
+uno_Mapping * createIdentityMapping(uno::Environment const & rEnv)
+{
+ return new IdentityMapping(rEnv);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/IdentityMapping.hxx b/cppu/source/uno/IdentityMapping.hxx
new file mode 100644
index 000000000..8ba081b00
--- /dev/null
+++ b/cppu/source/uno/IdentityMapping.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <uno/mapping.h>
+
+namespace com::sun::star::uno
+{
+class Environment;
+}
+
+uno_Mapping* createIdentityMapping(const css::uno::Environment& rEnv);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/any.cxx b/cppu/source/uno/any.cxx
new file mode 100644
index 000000000..e26b97286
--- /dev/null
+++ b/cppu/source/uno/any.cxx
@@ -0,0 +1,142 @@
+/* -*- 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 "copy.hxx"
+#include "destr.hxx"
+
+using namespace cppu;
+
+
+extern "C"
+{
+
+void SAL_CALL uno_type_any_assign(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructAny( pDest, release );
+ if (pType)
+ {
+ _copyConstructAny( pDest, pSource, pType, nullptr, acquire, nullptr );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_any_assign(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructAny( pDest, release );
+ if (pTypeDescr)
+ {
+ _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_type_any_construct(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ if (pType)
+ {
+ _copyConstructAny( pDest, pSource, pType, nullptr, acquire, nullptr );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_any_construct(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ if (pTypeDescr)
+ {
+ _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_type_any_constructAndConvert(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ if (pType)
+ {
+ _copyConstructAny( pDest, pSource, pType, nullptr, nullptr, mapping );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_any_constructAndConvert(
+ uno_Any * pDest, void * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ if (pTypeDescr)
+ {
+ _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, nullptr, mapping );
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDest );
+ }
+}
+
+void SAL_CALL uno_any_destruct( uno_Any * pValue, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructAny( pValue, release );
+}
+
+void SAL_CALL uno_any_clear( uno_Any * pValue, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructAny( pValue, release );
+ CONSTRUCT_EMPTY_ANY( pValue );
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/assign.hxx b/cppu/source/uno/assign.hxx
new file mode 100644
index 000000000..3e2893fde
--- /dev/null
+++ b/cppu/source/uno/assign.hxx
@@ -0,0 +1,449 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "prim.hxx"
+#include "destr.hxx"
+#include "constr.hxx"
+#include "copy.hxx"
+
+
+namespace cppu
+{
+
+
+//#### assignment ##################################################################################
+
+
+inline void _assignInterface(
+ void ** ppDest, void * pSource,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+
+{
+ _acquire( pSource, acquire );
+ void * const pToBeReleased = *ppDest;
+ *ppDest = pSource;
+ _release( pToBeReleased, release );
+}
+
+inline void * _queryInterface(
+ void * pSource,
+ typelib_TypeDescriptionReference * pDestType,
+ uno_QueryInterfaceFunc queryInterface )
+{
+ if (pSource)
+ {
+ if (nullptr == queryInterface)
+ queryInterface = binuno_queryInterface;
+ pSource = (*queryInterface)( pSource, pDestType );
+ }
+ return pSource;
+}
+
+bool assignStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release );
+
+inline bool _assignStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+{
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // copy base value
+ if (! assignStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription,
+ queryInterface, acquire, release ))
+ {
+ return false;
+ }
+ }
+ // then copy members
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+ while (nDescr--)
+ {
+ if (! ::uno_type_assignData( static_cast<char *>(pDest) + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr],
+ static_cast<char *>(pSource) + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr],
+ queryInterface, acquire, release ))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool _assignData(
+ void * pDest,
+ typelib_TypeDescriptionReference * pDestType, typelib_TypeDescription * pDestTypeDescr,
+ void * pSource,
+ typelib_TypeDescriptionReference * pSourceType, typelib_TypeDescription * pSourceTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+{
+ if (pDest == pSource)
+ return _type_equals( pDestType, pSourceType );
+
+ if (! pSource)
+ {
+ _destructData( pDest, pDestType, pDestTypeDescr, release );
+ _defaultConstructData( pDest, pDestType, pDestTypeDescr );
+ return true;
+ }
+ while (typelib_TypeClass_ANY == pSourceType->eTypeClass)
+ {
+ pSourceTypeDescr = nullptr;
+ pSourceType = static_cast<uno_Any *>(pSource)->pType;
+ pSource = static_cast<uno_Any *>(pSource)->pData;
+ if (pDest == pSource)
+ return true;
+ }
+
+ switch (pDestType->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ return pSourceType->eTypeClass == typelib_TypeClass_VOID;
+ case typelib_TypeClass_CHAR:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ *static_cast<sal_Unicode *>(pDest) = *static_cast<sal_Unicode *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_BOOLEAN:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast<sal_Bool *>(pDest) = bool(*static_cast<sal_Bool *>(pSource));
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_BYTE:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int8 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_SHORT:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_uInt16 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_uInt16 *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_LONG:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_uInt32 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_HYPER:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_LONG:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_uInt32 *>(pSource);
+ return true;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int64 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_LONG:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt32 *>(pSource);
+ return true;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt64 *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_FLOAT:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<float *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<float *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<float *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(pDest) = *static_cast<float *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_DOUBLE:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ *static_cast<double *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ return true;
+ case typelib_TypeClass_SHORT:
+ *static_cast<double *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<double *>(pDest) = *static_cast<sal_uInt16 *>(pSource);
+ return true;
+ case typelib_TypeClass_LONG:
+ *static_cast<double *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ return true;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<double *>(pDest) = *static_cast<sal_uInt32 *>(pSource);
+ return true;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<double *>(pDest) = *static_cast<float *>(pSource);
+ return true;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>(pDest) = *static_cast<double *>(pSource);
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_STRING:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_STRING:
+ ::rtl_uString_assign( static_cast<rtl_uString **>(pDest), *static_cast<rtl_uString **>(pSource) );
+ return true;
+ default:
+ return false;
+ }
+ case typelib_TypeClass_TYPE:
+ switch (pSourceType->eTypeClass)
+ {
+ case typelib_TypeClass_TYPE:
+ {
+ typelib_TypeDescriptionReference ** pp = static_cast<typelib_TypeDescriptionReference **>(pDest);
+ ::typelib_typedescriptionreference_release( *pp );
+ *pp = *static_cast<typelib_TypeDescriptionReference **>(pSource);
+ TYPE_ACQUIRE( *pp );
+ return true;
+ }
+ default:
+ return false;
+ }
+ case typelib_TypeClass_ANY:
+ _destructAny( static_cast<uno_Any *>(pDest), release );
+ _copyConstructAny( static_cast<uno_Any *>(pDest), pSource, pSourceType, pSourceTypeDescr, acquire, nullptr );
+ return true;
+ case typelib_TypeClass_ENUM:
+ if (_type_equals( pDestType, pSourceType ))
+ {
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ return true;
+ }
+ return false;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (typelib_TypeClass_STRUCT == pSourceType->eTypeClass ||
+ typelib_TypeClass_EXCEPTION == pSourceType->eTypeClass)
+ {
+ bool bRet = false;
+ if (pSourceTypeDescr)
+ {
+ typelib_CompoundTypeDescription * pTypeDescr =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pSourceTypeDescr);
+ while (pTypeDescr &&
+ !_type_equals(pTypeDescr->aBase.pWeakRef, pDestType))
+ {
+ pTypeDescr = pTypeDescr->pBaseTypeDescription;
+ }
+ if (pTypeDescr)
+ {
+ bRet = _assignStruct(
+ pDest, pSource, pTypeDescr, queryInterface, acquire, release );
+ }
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pSourceTypeDescr, pSourceType );
+ typelib_CompoundTypeDescription * pTypeDescr =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pSourceTypeDescr);
+ while (pTypeDescr &&
+ !_type_equals(pTypeDescr->aBase.pWeakRef, pDestType))
+ {
+ pTypeDescr = pTypeDescr->pBaseTypeDescription;
+ }
+ if (pTypeDescr)
+ {
+ bRet = _assignStruct(
+ pDest, pSource, pTypeDescr, queryInterface, acquire, release );
+ }
+ TYPELIB_DANGER_RELEASE( pSourceTypeDescr );
+ }
+ return bRet;
+ }
+ return false;
+ case typelib_TypeClass_SEQUENCE:
+ if (!_type_equals( pDestType, pSourceType ))
+ return false;
+ // check self assignment (only after _type_equals, to account for shared static empty):
+ if (*static_cast<uno_Sequence **>(pSource) != *static_cast<uno_Sequence **>(pDest))
+ {
+ osl_atomic_increment( &(*static_cast<uno_Sequence **>(pSource))->nRefCount );
+ idestructSequence(
+ *static_cast<uno_Sequence **>(pDest), pDestType, pDestTypeDescr, release );
+ *static_cast<uno_Sequence **>(pDest) = *static_cast<uno_Sequence **>(pSource);
+ }
+ return true;
+ case typelib_TypeClass_INTERFACE:
+ if (typelib_TypeClass_INTERFACE != pSourceType->eTypeClass)
+ return false;
+ if (_type_equals( pDestType, pSourceType ))
+ {
+ _assignInterface( static_cast<void **>(pDest), *static_cast<void **>(pSource), acquire, release );
+ return true;
+ }
+ else if (*static_cast< void ** >(pSource) == nullptr)
+ {
+ // A null reference of any interface type can be converted to a null
+ // reference of any other interface type:
+ void * const pToBeReleased = *static_cast< void ** >(pDest);
+ *static_cast< void ** >(pDest) = nullptr;
+ _release( pToBeReleased, release );
+ return true;
+ }
+ else
+ {
+ if (pSourceTypeDescr)
+ {
+ typelib_TypeDescription * pTD = pSourceTypeDescr;
+ while (pTD && !_type_equals( pTD->pWeakRef, pDestType ))
+ {
+ pTD = &reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+ }
+ if (pTD) // is base of dest
+ {
+ _assignInterface( static_cast<void **>(pDest), *static_cast<void **>(pSource), acquire, release );
+ return true;
+ }
+ }
+
+ // query for interface:
+ void * pQueried = _queryInterface( *static_cast<void **>(pSource),
+ pDestType, queryInterface );
+ if (pQueried != nullptr) {
+ void * const pToBeReleased = *static_cast<void **>(pDest);
+ *static_cast<void **>(pDest) = pQueried;
+ _release( pToBeReleased, release );
+ }
+ return (pQueried != nullptr);
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/cascade_mapping.cxx b/cppu/source/uno/cascade_mapping.cxx
new file mode 100644
index 000000000..f03d88e52
--- /dev/null
+++ b/cppu/source/uno/cascade_mapping.cxx
@@ -0,0 +1,308 @@
+/* -*- 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/interlck.h>
+#include <rtl/ustring.hxx>
+#include <uno/environment.hxx>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+#include <uno/dispatcher.h>
+#include <o3tl/string_view.hxx>
+
+#include <cppu/EnvDcp.hxx>
+
+#include "cascade_mapping.hxx"
+
+using namespace com::sun::star;
+
+namespace {
+
+class MediatorMapping : public uno_Mapping
+{
+ oslInterlockedCount m_refCount;
+
+ uno::Mapping m_from2uno;
+ uno::Mapping m_uno2to;
+
+ uno::Environment m_from;
+ uno::Environment m_interm;
+ uno::Environment m_to;
+
+public:
+ void acquire();
+ void release();
+
+ void mapInterface(void ** ppOut,
+ void * pInterface,
+ typelib_InterfaceTypeDescription * pInterfaceTypeDescr);
+ MediatorMapping(uno_Environment * pFrom,
+ uno_Environment * pInterm,
+ uno_Environment * pTo);
+};
+
+}
+
+extern "C" {
+static void s_acquire(uno_Mapping * mapping)
+{
+ MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
+ pMediatorMapping->acquire();
+}
+
+static void s_release(uno_Mapping * mapping)
+{
+ MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
+ pMediatorMapping->release();
+}
+
+static void s_mapInterface(
+ uno_Mapping * mapping,
+ void ** ppOut,
+ void * pInterface,
+ typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
+{
+ MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
+ pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr);
+}
+}
+
+MediatorMapping::MediatorMapping(uno_Environment * pFrom,
+ uno_Environment * pInterm,
+ uno_Environment * pTo)
+ : m_refCount(0),
+ m_from2uno(pFrom, pInterm),
+ m_uno2to (pInterm, pTo),
+ m_from (pFrom),
+ m_interm (pInterm),
+ m_to (pTo)
+{
+ if (!m_from2uno.get() || !m_uno2to.get())
+ abort();
+
+ uno_Mapping::acquire = s_acquire;
+ uno_Mapping::release = s_release;
+ uno_Mapping::mapInterface = s_mapInterface;
+}
+
+void MediatorMapping::acquire()
+{
+ osl_atomic_increment(&m_refCount);
+}
+
+void MediatorMapping::release()
+{
+ if (osl_atomic_decrement(&m_refCount) == 0)
+ {
+ ::uno_revokeMapping(this);
+ }
+}
+
+extern "C" { static void s_mapInterface_v(va_list * pParam)
+{
+ void ** ppOut = va_arg(*pParam, void **);
+ void * pInterface = va_arg(*pParam, void *);
+ typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
+ uno_Mapping * pMapping = va_arg(*pParam, uno_Mapping *);
+
+ pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr);
+}}
+
+void MediatorMapping::mapInterface(
+ void ** ppOut,
+ void * pInterface,
+ typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
+{
+ if (*ppOut != nullptr)
+ {
+ uno_ExtEnvironment * env = m_to.get()->pExtEnv;
+ OSL_ASSERT( env != nullptr );
+ env->releaseInterface( env, *ppOut );
+ *ppOut = nullptr;
+ }
+
+ void * ret = nullptr;
+ uno_Interface * pUnoI = nullptr;
+
+ m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get());
+
+ m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr);
+
+ if (pUnoI)
+ m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI);
+
+ *ppOut = ret;
+}
+
+extern "C" { static void s_MediatorMapping_free(uno_Mapping * pMapping)
+ SAL_THROW_EXTERN_C()
+{
+ delete static_cast<MediatorMapping *>(pMapping);
+}}
+
+
+static OUString getPrefix(std::u16string_view str1, std::u16string_view str2)
+{
+ sal_Int32 nIndex1 = 0;
+ sal_Int32 nIndex2 = 0;
+ sal_Int32 sim = 0;
+
+ std::u16string_view token1;
+ std::u16string_view token2;
+
+ do
+ {
+ token1 = o3tl::getToken(str1, 0, ':', nIndex1);
+ token2 = o3tl::getToken(str2, 0, ':', nIndex2);
+
+ if (token1 == token2)
+ sim += token1.size() + 1;
+ }
+ while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2);
+
+ OUString result;
+
+ if (sim)
+ result = str1.substr(0, sim - 1);
+
+ return result;
+}
+
+// OUString str1("abc:def:ghi");
+// OUString str2("abc:def");
+// OUString str3("abc");
+// OUString str4("");
+
+// OUString pref;
+
+// pref = getPrefix(str1, str1);
+// pref = getPrefix(str1, str2);
+// pref = getPrefix(str1, str3);
+// pref = getPrefix(str1, str4);
+
+// pref = getPrefix(str2, str1);
+// pref = getPrefix(str3, str1);
+// pref = getPrefix(str4, str1);
+
+
+void getCascadeMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo,
+ rtl_uString * pAddPurpose)
+{
+ if (pAddPurpose && pAddPurpose->length)
+ return;
+
+ OUString uno_envType(UNO_LB_UNO);
+
+ OUString from_envType = cppu::EnvDcp::getTypeName(pFrom->pTypeName);
+ OUString to_envType = cppu::EnvDcp::getTypeName(pTo->pTypeName);
+ OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName);
+ OUString to_envPurpose = cppu::EnvDcp::getPurpose(pTo->pTypeName);
+
+#ifdef LOG_CALLING_named_purpose_getMapping
+ OString s_from_name = OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US);
+ OString s_to_name = OUStringToOString(pTo->pTypeName, RTL_TEXTENCODING_ASCII_US);
+
+ std::cerr << __FUNCTION__ << " - creating mediation ";
+ std::cerr << "pFrom: " << s_from_name.getStr();
+ std::cerr <<" pTo: " << s_to_name.getStr() << std::endl;
+#endif
+
+ if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla
+ return;
+
+ // reaching this point means, we need a mediated mapping!!!
+ // we generally mediate via uno[:free]
+ uno_Environment * pInterm = nullptr;
+
+ // chained uno -> uno
+ if (from_envType == uno_envType && to_envType == uno_envType)
+ {
+ OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
+
+ OUString uno_envDcp = uno_envType + purpose;
+
+ // direct mapping possible?
+ // uno:bla-->uno:bla:blubb
+ if (from_envPurpose == purpose)
+ {
+ OUString rest = to_envPurpose.copy(purpose.getLength());
+
+ sal_Int32 index = rest.indexOf(':', 1);
+ if (index == -1)
+ {
+ uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
+ return;
+ }
+
+ uno_envDcp += rest.subView(0, index);
+ }
+ else if (to_envPurpose == purpose)
+ {
+ OUString rest = from_envPurpose.copy(purpose.getLength());
+
+ sal_Int32 index = rest.indexOf(':', 1);
+ if (index == -1)
+ {
+ uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
+ return;
+ }
+
+ uno_envDcp += rest.subView(0, index);
+ }
+
+ uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr);
+ }
+ else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ?
+ // mediate via uno:purpose(fromEnv)
+ {
+ OUString envDcp = uno_envType + from_envPurpose;
+ uno_getEnvironment(&pInterm, envDcp.pData, nullptr);
+ }
+ else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>?
+ // mediate via uno(context)
+ {
+ OUString envDcp = uno_envType + to_envPurpose;
+ uno_getEnvironment(&pInterm, envDcp.pData, nullptr);
+ }
+ else // everything else
+ // mediate via uno:purpose
+ {
+ OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
+
+ OUString uno_envDcp = uno_envType + purpose;
+
+ uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr);
+ }
+
+ uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo);
+ pInterm->release(pInterm);
+
+
+ pMapping->acquire(pMapping);
+
+ ::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose);
+
+ if (*ppMapping)
+ (*ppMapping)->release(*ppMapping);
+
+ *ppMapping = pMapping;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/cascade_mapping.hxx b/cppu/source/uno/cascade_mapping.hxx
new file mode 100644
index 000000000..438143f6b
--- /dev/null
+++ b/cppu/source/uno/cascade_mapping.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <uno/environment.h>
+#include <uno/mapping.h>
+#include <rtl/ustring.h>
+
+
+void getCascadeMapping(uno_Mapping ** ppMapping,
+ uno_Environment * pFrom,
+ uno_Environment * pTo,
+ rtl_uString * pAddPurpose );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/check.cxx b/cppu/source/uno/check.cxx
new file mode 100644
index 000000000..561434aa5
--- /dev/null
+++ b/cppu/source/uno/check.cxx
@@ -0,0 +1,335 @@
+/* -*- 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 <cppu/macros.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <uno/any2.h>
+
+
+namespace {
+
+#if defined( _WIN32)
+#pragma pack(push, 8)
+#endif
+
+struct C1
+{
+ sal_Int16 n1;
+};
+struct C2 : public C1
+{
+ sal_Int32 n2 CPPU_GCC3_ALIGN( C1 );
+};
+struct C3 : public C2
+{
+ double d3;
+ sal_Int32 n3;
+};
+struct C4 : public C3
+{
+ sal_Int32 n4 CPPU_GCC3_ALIGN( C3 );
+ double d4;
+};
+struct C5 : public C4
+{
+ sal_Int64 n5;
+ sal_Bool b5;
+};
+struct C6 : public C1
+{
+ C5 c6 CPPU_GCC3_ALIGN( C1 );
+ sal_Bool b6;
+};
+
+struct D
+{
+ sal_Int16 d;
+ sal_Int32 e;
+};
+struct E
+{
+ // [-loplugin:fakebool] false positive:
+ sal_Bool a;
+ // [-loplugin:fakebool] false positive:
+ sal_Bool b;
+ // [-loplugin:fakebool] false positive:
+ sal_Bool c;
+ sal_Int16 d;
+ sal_Int32 e;
+};
+
+struct M
+{
+ sal_Int32 n;
+ sal_Int16 o;
+};
+
+struct N : public M
+{
+ sal_Int16 p CPPU_GCC3_ALIGN( M );
+};
+struct N2
+{
+ M m;
+ sal_Int16 p;
+};
+
+struct O : public M
+{
+ double p;
+ sal_Int16 q;
+};
+struct O2 : public O
+{
+ sal_Int16 p2 CPPU_GCC3_ALIGN( O );
+};
+
+struct P : public N
+{
+ double p2;
+};
+
+struct empty
+{
+};
+struct second : public empty
+{
+ int a;
+};
+
+struct AlignSize_Impl
+{
+ sal_Int16 nInt16;
+ double dDouble;
+};
+
+struct Char1
+{
+ char c1;
+};
+struct Char2 : public Char1
+{
+ char c2 CPPU_GCC3_ALIGN( Char1 );
+};
+struct Char3 : public Char2
+{
+ char c3 CPPU_GCC3_ALIGN( Char2 );
+};
+enum Enum
+{
+ v = SAL_MAX_ENUM
+};
+
+#ifdef _WIN32
+# pragma pack(pop)
+#endif
+
+// [-loplugin:fakebool] false positive:
+static_assert( static_cast<sal_Bool>(true) == sal_True,
+ "must be binary compatible" );
+// [-loplugin:fakebool] false positive:
+static_assert( static_cast<sal_Bool>(false) == sal_False,
+ "must be binary compatible" );
+#if SAL_TYPES_ALIGNMENT8 == 2
+static_assert(offsetof(AlignSize_Impl, dDouble) == 2, "offsetof(AlignSize_Impl, dDouble) != 2");
+static_assert(sizeof(AlignSize_Impl) == 10, "sizeof(AlignSize_Impl) != 10");
+#elif SAL_TYPES_ALIGNMENT8 == 4
+static_assert(offsetof(AlignSize_Impl, dDouble) == 4, "offsetof(AlignSize_Impl, dDouble) != 4");
+static_assert(sizeof(AlignSize_Impl) == 12, "sizeof(AlignSize_Impl) != 12");
+#elif SAL_TYPES_ALIGNMENT8 == 8
+static_assert(offsetof(AlignSize_Impl, dDouble) == 8, "offsetof(AlignSize_Impl, dDouble) != 8");
+static_assert(sizeof(AlignSize_Impl) == 16, "sizeof(AlignSize_Impl) != 16");
+#else
+# error unexpected alignment of 8 byte types
+#endif
+
+// sequence
+static_assert((SAL_SEQUENCE_HEADER_SIZE % 8) == 0, "binary compatibility test failed: (SAL_SEQUENCE_HEADER_SIZE % 8) == 0!!!");
+// enum
+static_assert(sizeof(Enum) == sizeof(sal_Int32), "binary compatibility test failed: (sizeof(Enum) == sizeof(sal_Int32))");
+// any
+static_assert(sizeof(void *) >= sizeof(sal_Int32), "binary compatibility test failed: (sizeof(void *) >= sizeof(sal_Int32))");
+static_assert(sizeof(uno_Any) == sizeof(void *) * 3, "binary compatibility test failed: (sizeof(uno_Any) == sizeof(void *) * 3");
+static_assert(offsetof(uno_Any, pType) == 0, "offsetof(uno_Any, pType) != 0");
+static_assert(offsetof(uno_Any, pData) == 1 * sizeof(void *), "offsetof(uno_Any, pTData) != (1 * sizeof(void *))");
+static_assert(offsetof(uno_Any, pReserved) == 2 * sizeof(void *), "offsetof(uno_Any, pReserved) != (2 * sizeof(void *))");
+// string
+static_assert(sizeof(OUString) == sizeof(rtl_uString *), "binary compatibility test failed: sizeof(OUString) != sizeof(rtl_uString *)");
+// struct
+#if SAL_TYPES_ALIGNMENT8 == 2
+static_assert(sizeof(M) == 6, "sizeof(M) != 6");
+static_assert(sizeof(N) == 8, "sizeof(N) != 8");
+static_assert(sizeof(N2) == 8, "sizeof(N2) != 8");
+static_assert(offsetof(N2, p) == 6, "offsetof(N2, p) != 6");
+#else
+static_assert(sizeof(M) == 8, "sizeof(M) != 8");
+static_assert(sizeof(N) == 12, "sizeof(N) != 12");
+static_assert(sizeof(N2) == 12, "sizeof(N2) != 12");
+static_assert(offsetof(N2, p) == 8, "offsetof(N2, p) != 8");
+#endif
+static_assert(offsetof(M, o) == 4, "offsetof(M, o) != 4");
+
+#if SAL_TYPES_ALIGNMENT8 == 2
+static_assert(sizeof(O) == 16, "sizeof(O) != 16");
+#elif SAL_TYPES_ALIGNMENT8 == 4
+static_assert(sizeof(O) == 20, "sizeof(O) != 20");
+#elif SAL_TYPES_ALIGNMENT8 == 8
+static_assert(sizeof(O) == 24, "sizeof(O) != 24");
+#else
+# error unexpected alignment of 8 byte types
+#endif
+
+#if SAL_TYPES_ALIGNMENT8 == 2
+static_assert(sizeof(C2) == 6, "sizeof(C2) != 6");
+static_assert(sizeof(D) == 6, "sizeof(D) != 6");
+static_assert(offsetof(D, e) == 2, "offsetof(D, e) != 2");
+static_assert(offsetof(E, e) == 6, "offsetof(E, e) != 6");
+#else
+static_assert(sizeof(C2) == 8, "sizeof(C2) != 8");
+static_assert(sizeof(D) == 8, "sizeof(D) != 8");
+static_assert(offsetof(D, e) == 4, "offsetof(D, e) != 4");
+static_assert(offsetof(E, e) == 8, "offsetof(E, e) != 8");
+#endif
+
+static_assert(sizeof(C1) == 2, "sizeof(C1) != 2");
+static_assert(offsetof(E, d) == 4, "offsetof(E, d) != 4");
+
+#if SAL_TYPES_ALIGNMENT8 == 2
+static_assert(sizeof(C3) == 18, "sizeof(C3) != 18");
+static_assert(sizeof(C4) == 30, "sizeof(C4) != 30");
+static_assert(sizeof(C5) == 40, "sizeof(C5) != 40");
+static_assert(sizeof(C6) == 44, "sizeof(C6) != 44");
+
+static_assert(sizeof(O2) == 18, "sizeof(O2) != 18");
+#elif SAL_TYPES_ALIGNMENT8 == 4
+static_assert(sizeof(C3) == 20, "sizeof(C3) != 20");
+static_assert(sizeof(C4) == 32, "sizeof(C4) != 32");
+static_assert(sizeof(C5) == 44, "sizeof(C5) != 44");
+static_assert(sizeof(C6) == 52, "sizeof(C6) != 52");
+
+static_assert(sizeof(O2) == 24, "sizeof(O2) != 24");
+#elif SAL_TYPES_ALIGNMENT8 == 8
+static_assert(sizeof(C3) == 24, "sizeof(C3) != 24");
+static_assert(sizeof(C4) == 40, "sizeof(C4) != 40");
+static_assert(sizeof(C5) == 56, "sizeof(C5) != 56");
+static_assert(sizeof(C6) == 72, "sizeof(C6) != 72");
+
+static_assert(sizeof(O2) == 32, "sizeof(O2) != 32");
+#else
+# error unexpected alignment of 8 byte types
+#endif
+
+static_assert(sizeof(Char3) == 3, "sizeof(Char3) != 3");
+
+#if SAL_TYPES_ALIGNMENT8 == 2
+// max alignment is 2
+static_assert(sizeof(P) == 16, "sizeof(P) != 16");
+#elif SAL_TYPES_ALIGNMENT8 == 4
+// max alignment is 4
+static_assert(sizeof(P) == 20, "sizeof(P) != 20");
+#elif SAL_TYPES_ALIGNMENT8 == 8
+// alignment of P is 8, because of P[] ...
+static_assert(sizeof(P) == 24, "sizeof(P) != 24");
+static_assert(sizeof(second) == sizeof(int), "sizeof(second) != sizeof(int)");
+#else
+# error unexpected alignment of 8 byte types
+#endif
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+
+struct Char4
+{
+#if defined __GNUC__ && (__GNUC__ < 12 || (__GNUC__ == 12 && __GNUC_MINOR__ < 1)) && !defined __clang__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes"
+#endif
+ [[maybe_unused]] Char3 chars;
+#if defined __GNUC__ && (__GNUC__ < 12 || (__GNUC__ == 12 && __GNUC_MINOR__ < 1)) && !defined __clang__
+#pragma GCC diagnostic pop
+#endif
+ char c;
+};
+
+template<typename T1, typename T2> std::size_t OFFSET_OF(T2 T1::* p) {
+ return reinterpret_cast< size_t >(reinterpret_cast<char *>(&(reinterpret_cast<T1 *>(16)->*p)) -16);
+}
+
+class BinaryCompatible_Impl
+{
+public:
+ BinaryCompatible_Impl();
+};
+BinaryCompatible_Impl::BinaryCompatible_Impl()
+{
+ assert(OFFSET_OF(&N::p) == 8);
+
+ assert(OFFSET_OF(&C2::n2) == 4);
+
+#if SAL_TYPES_ALIGNMENT8 == 2
+ assert(OFFSET_OF(&C3::d3) == 6);
+ assert(OFFSET_OF(&C3::n3) == 14);
+ assert(OFFSET_OF(&C4::n4) == 18);
+ assert(OFFSET_OF(&C4::d4) == 22);
+ assert(OFFSET_OF(&C5::n5) == 30);
+ assert(OFFSET_OF(&C5::b5) == 38);
+ assert(OFFSET_OF(&C6::c6) == 2);
+ assert(OFFSET_OF(&C6::b6) == 42);
+
+ assert(OFFSET_OF(&O2::p2) == 16);
+#elif SAL_TYPES_ALIGNMENT8 == 4
+ assert(OFFSET_OF(&C3::d3) == 8);
+ assert(OFFSET_OF(&C3::n3) == 16);
+ assert(OFFSET_OF(&C4::n4) == 20);
+ assert(OFFSET_OF(&C4::d4) == 24);
+ assert(OFFSET_OF(&C5::n5) == 32);
+ assert(OFFSET_OF(&C5::b5) == 40);
+ assert(OFFSET_OF(&C6::c6) == 4);
+ assert(OFFSET_OF(&C6::b6) == 48);
+
+ assert(OFFSET_OF(&O2::p2) == 20);
+#elif SAL_TYPES_ALIGNMENT8 == 8
+ assert(OFFSET_OF(&C3::d3) == 8);
+ assert(OFFSET_OF(&C3::n3) == 16);
+ assert(OFFSET_OF(&C4::n4) == 24);
+ assert(OFFSET_OF(&C4::d4) == 32);
+ assert(OFFSET_OF(&C5::n5) == 40);
+ assert(OFFSET_OF(&C5::b5) == 48);
+ assert(OFFSET_OF(&C6::c6) == 8);
+ assert(OFFSET_OF(&C6::b6) == 64);
+
+ assert(OFFSET_OF(&O2::p2) == 24);
+#else
+# error unexpected alignment of 8 byte types
+#endif
+
+ assert(OFFSET_OF(&Char4::c) == 3);
+}
+
+BinaryCompatible_Impl aTest;
+
+#endif
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/constr.hxx b/cppu/source/uno/constr.hxx
new file mode 100644
index 000000000..9ca2eebf8
--- /dev/null
+++ b/cppu/source/uno/constr.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "prim.hxx"
+#include <osl/diagnose.h>
+
+namespace cppu
+{
+
+
+//#### construction ################################################################################
+
+
+void defaultConstructStruct(
+ void * pMem,
+ typelib_CompoundTypeDescription * pCompType );
+
+inline void _defaultConstructStruct(
+ void * pMem,
+ typelib_CompoundTypeDescription * pTypeDescr )
+{
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ defaultConstructStruct( pMem, pTypeDescr->pBaseTypeDescription );
+ }
+
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+
+ while (nDescr--)
+ {
+ ::uno_type_constructData( static_cast<char *>(pMem) + pMemberOffsets[nDescr], ppTypeRefs[nDescr] );
+ }
+}
+
+
+inline void _defaultConstructData(
+ void * pMem,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr )
+{
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ *static_cast<sal_Unicode *>(pMem) = '\0';
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast<sal_Bool *>(pMem) = false;
+ break;
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int8 *>(pMem) = 0;
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int16 *>(pMem) = 0;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int32 *>(pMem) = 0;
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_Int64 *>(pMem) = 0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(pMem) = 0.0;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>(pMem) = 0.0;
+ break;
+ case typelib_TypeClass_STRING:
+ *static_cast<rtl_uString **>(pMem) = nullptr;
+ ::rtl_uString_new( static_cast<rtl_uString **>(pMem) );
+ break;
+ case typelib_TypeClass_TYPE:
+ *static_cast<typelib_TypeDescriptionReference **>(pMem) = _getVoidType();
+ break;
+ case typelib_TypeClass_ANY:
+ CONSTRUCT_EMPTY_ANY( static_cast<uno_Any *>(pMem) );
+ break;
+ case typelib_TypeClass_ENUM:
+ if (pTypeDescr)
+ {
+ *static_cast<sal_Int32 *>(pMem) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue;
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ *static_cast<sal_Int32 *>(pMem) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue;
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (pTypeDescr)
+ {
+ _defaultConstructStruct( pMem, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ _defaultConstructStruct( pMem, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ *static_cast<uno_Sequence **>(pMem) = createEmptySequence();
+ break;
+ case typelib_TypeClass_INTERFACE:
+ *static_cast<void **>(pMem) = nullptr; // either cpp or c-uno interface
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/copy.hxx b/cppu/source/uno/copy.hxx
new file mode 100644
index 000000000..6a71d413f
--- /dev/null
+++ b/cppu/source/uno/copy.hxx
@@ -0,0 +1,655 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "prim.hxx"
+#include "constr.hxx"
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <type_traits>
+
+namespace cppu
+{
+
+
+//#### copy construction ###########################################################################
+
+namespace {
+
+// The non-dynamic prefix of sal_Sequence (aka uno_Sequence):
+struct SequencePrefix {
+ sal_Int32 nRefCount;
+ sal_Int32 nElements;
+};
+static_assert(sizeof (SequencePrefix) < sizeof (uno_Sequence));
+static_assert(offsetof(SequencePrefix, nRefCount) == offsetof(uno_Sequence, nRefCount));
+static_assert(
+ std::is_same_v<decltype(SequencePrefix::nRefCount), decltype(uno_Sequence::nRefCount)>);
+static_assert(offsetof(SequencePrefix, nElements) == offsetof(uno_Sequence, nElements));
+static_assert(
+ std::is_same_v<decltype(SequencePrefix::nElements), decltype(uno_Sequence::nElements)>);
+
+}
+
+inline uno_Sequence * allocSeq(
+ sal_Int32 nElementSize, sal_Int32 nElements )
+{
+ OSL_ASSERT( nElements >= 0 && nElementSize >= 0 );
+ uno_Sequence * pSeq = nullptr;
+ sal_uInt32 nSize = calcSeqMemSize( nElementSize, nElements );
+ if (nSize > 0)
+ {
+ pSeq = static_cast<uno_Sequence *>(std::malloc( nSize ));
+ if (pSeq != nullptr)
+ {
+ // header init, going via SequencePrefix to avoid UBSan insufficient-object-size
+ // warnings when `nElements == 0` and thus `nSize < sizeof (uno_Sequence)`:
+ auto const header = reinterpret_cast<SequencePrefix *>(pSeq);
+ header->nRefCount = 1;
+ header->nElements = nElements;
+ }
+ }
+ return pSeq;
+}
+
+
+void copyConstructStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping );
+
+inline void _copyConstructStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // copy base value
+ copyConstructStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, acquire, mapping );
+ }
+
+ // then copy members
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+
+ if (mapping)
+ {
+ while (nDescr--)
+ {
+ ::uno_type_copyAndConvertData(
+ static_cast<char *>(pDest) + pMemberOffsets[nDescr],
+ static_cast<char *>(pSource) + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr], mapping );
+ }
+ }
+ else
+ {
+ while (nDescr--)
+ {
+ ::uno_type_copyData(
+ static_cast<char *>(pDest) + pMemberOffsets[nDescr],
+ static_cast<char *>(pSource) + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr], acquire );
+ }
+ }
+}
+
+
+uno_Sequence * copyConstructSequence(
+ uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_AcquireFunc acquire, uno_Mapping * mapping );
+
+
+inline void _copyConstructAnyFromData(
+ uno_Any * pDestAny, void * pSource,
+ typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ TYPE_ACQUIRE( pType );
+ pDestAny->pType = pType;
+
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Unicode *>(pDestAny->pData) = *static_cast<sal_Unicode *>(pSource);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Bool *>(pDestAny->pData) = bool(*static_cast<sal_Bool *>(pSource));
+ break;
+ case typelib_TypeClass_BYTE:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int8 *>(pDestAny->pData) = *static_cast<sal_Int8 *>(pSource);
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int16 *>(pDestAny->pData) = *static_cast<sal_Int16 *>(pSource);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int32 *>(pDestAny->pData) = *static_cast<sal_Int32 *>(pSource);
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof(void *) >= sizeof(sal_Int64))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(sal_Int64) );
+ assert(pDestAny->pData);
+ *static_cast<sal_Int64 *>(pDestAny->pData) = *static_cast<sal_Int64 *>(pSource);
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof(void *) >= sizeof(float))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(float) );
+ assert(pDestAny->pData);
+ *static_cast<float *>(pDestAny->pData) = *static_cast<float *>(pSource);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof(void *) >= sizeof(double))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(double) );
+ assert(pDestAny->pData);
+ *static_cast<double *>(pDestAny->pData) = *static_cast<double *>(pSource);
+ break;
+ case typelib_TypeClass_STRING:
+ ::rtl_uString_acquire( *static_cast<rtl_uString **>(pSource) );
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<rtl_uString **>(pDestAny->pData) = *static_cast<rtl_uString **>(pSource);
+ break;
+ case typelib_TypeClass_TYPE:
+ TYPE_ACQUIRE( *static_cast<typelib_TypeDescriptionReference **>(pSource) );
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<typelib_TypeDescriptionReference **>(pDestAny->pData) = *static_cast<typelib_TypeDescriptionReference **>(pSource);
+ break;
+ case typelib_TypeClass_ANY:
+ OSL_FAIL( "### unexpected nested any!" );
+ break;
+ case typelib_TypeClass_ENUM:
+ pDestAny->pData = &pDestAny->pReserved;
+ // enum is forced to 32bit long
+ *static_cast<sal_Int32 *>(pDestAny->pData) = *static_cast<sal_Int32 *>(pSource);
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (pTypeDescr)
+ {
+ pDestAny->pData = std::malloc( pTypeDescr->nSize );
+ _copyConstructStruct(
+ pDestAny->pData, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr),
+ acquire, mapping );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ pDestAny->pData = std::malloc( pTypeDescr->nSize );
+ _copyConstructStruct(
+ pDestAny->pData, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr),
+ acquire, mapping );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ pDestAny->pData = &pDestAny->pReserved;
+ if (pTypeDescr)
+ {
+ *static_cast<uno_Sequence **>(pDestAny->pData) = copyConstructSequence(
+ *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ acquire, mapping );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ *static_cast<uno_Sequence **>(pDestAny->pData) = copyConstructSequence(
+ *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ acquire, mapping );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_INTERFACE:
+ pDestAny->pData = &pDestAny->pReserved;
+ if (mapping)
+ {
+ pDestAny->pReserved = _map( *static_cast<void **>(pSource), pType, pTypeDescr, mapping );
+ }
+ else
+ {
+ pDestAny->pReserved = *static_cast<void **>(pSource);
+ _acquire( pDestAny->pReserved, acquire );
+ }
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+}
+
+inline void _copyConstructAny(
+ uno_Any * pDestAny, void * pSource,
+ typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ if (typelib_TypeClass_VOID == pType->eTypeClass)
+ {
+ CONSTRUCT_EMPTY_ANY( pDestAny );
+ }
+ else
+ {
+ if (typelib_TypeClass_ANY == pType->eTypeClass)
+ {
+ if (pSource)
+ {
+ pType = static_cast<uno_Any *>(pSource)->pType;
+ if (typelib_TypeClass_VOID == pType->eTypeClass)
+ {
+ CONSTRUCT_EMPTY_ANY( pDestAny );
+ return;
+ }
+ pTypeDescr = nullptr;
+ pSource = static_cast<uno_Any *>(pSource)->pData;
+ }
+ else
+ {
+ CONSTRUCT_EMPTY_ANY( pDestAny );
+ return;
+ }
+ }
+ if (pSource)
+ {
+ _copyConstructAnyFromData( pDestAny, pSource, pType, pTypeDescr, acquire, mapping );
+ }
+ else // default construct
+ {
+ TYPE_ACQUIRE( pType );
+ pDestAny->pType = pType;
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Unicode *>(pDestAny->pData) = '\0';
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Bool *>(pDestAny->pData) = false;
+ break;
+ case typelib_TypeClass_BYTE:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int8 *>(pDestAny->pData) = 0;
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int16 *>(pDestAny->pData) = 0;
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<sal_Int32 *>(pDestAny->pData) = 0;
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof(void *) >= sizeof(sal_Int64))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(sal_Int64) );
+ assert(pDestAny->pData);
+ *static_cast<sal_Int64 *>(pDestAny->pData) = 0;
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof(void *) >= sizeof(float))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(float) );
+ assert(pDestAny->pData);
+ *static_cast<float *>(pDestAny->pData) = 0.0;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof(void *) >= sizeof(double))
+ pDestAny->pData = &pDestAny->pReserved;
+ else
+ pDestAny->pData = std::malloc( sizeof(double) );
+ assert(pDestAny->pData);
+ *static_cast<double *>(pDestAny->pData) = 0.0;
+ break;
+ case typelib_TypeClass_STRING:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<rtl_uString **>(pDestAny->pData) = nullptr;
+ ::rtl_uString_new( static_cast<rtl_uString **>(pDestAny->pData) );
+ break;
+ case typelib_TypeClass_TYPE:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<typelib_TypeDescriptionReference **>(pDestAny->pData) = _getVoidType();
+ break;
+ case typelib_TypeClass_ENUM:
+ pDestAny->pData = &pDestAny->pReserved;
+ if (pTypeDescr)
+ {
+ *static_cast<sal_Int32 *>(pDestAny->pData) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue;
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ *static_cast<sal_Int32 *>(pDestAny->pData) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue;
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (pTypeDescr)
+ {
+ pDestAny->pData = std::malloc( pTypeDescr->nSize );
+ _defaultConstructStruct(
+ pDestAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ pDestAny->pData = std::malloc( pTypeDescr->nSize );
+ _defaultConstructStruct(
+ pDestAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ pDestAny->pData = &pDestAny->pReserved;
+ *static_cast<uno_Sequence **>(pDestAny->pData) = createEmptySequence();
+ break;
+ case typelib_TypeClass_INTERFACE:
+ pDestAny->pData = &pDestAny->pReserved;
+ pDestAny->pReserved = nullptr; // either cpp or c-uno interface
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+ }
+ }
+}
+
+inline uno_Sequence * icopyConstructSequence(
+ uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ typelib_TypeClass eTypeClass = pElementType->eTypeClass;
+ if (!mapping ||
+ (eTypeClass <= typelib_TypeClass_ENUM &&
+ eTypeClass != typelib_TypeClass_ANY))
+ {
+ osl_atomic_increment( &pSource->nRefCount );
+ return pSource;
+ }
+ else // create new sequence
+ {
+ uno_Sequence * pDest;
+ sal_Int32 nElements = pSource->nElements;
+ if (nElements)
+ {
+ switch (eTypeClass)
+ {
+ case typelib_TypeClass_ANY:
+ {
+ pDest = allocSeq( sizeof (uno_Any), nElements );
+ if (pDest != nullptr)
+ {
+ uno_Any * pDestElements = reinterpret_cast<uno_Any *>(pDest->elements);
+ uno_Any * pSourceElements = reinterpret_cast<uno_Any *>(pSource->elements);
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ typelib_TypeDescriptionReference * pType =
+ pSourceElements[nPos].pType;
+ if (typelib_TypeClass_VOID == pType->eTypeClass)
+ {
+ CONSTRUCT_EMPTY_ANY( &pDestElements[nPos] );
+ }
+ else
+ {
+ _copyConstructAnyFromData(
+ &pDestElements[nPos],
+ pSourceElements[nPos].pData,
+ pType, nullptr,
+ acquire, mapping );
+ }
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 nElementSize = pElementTypeDescr->nSize;
+ char * pSourceElements = pSource->elements;
+ pDest = allocSeq( nElementSize, nElements );
+ if (pDest != nullptr)
+ {
+ char * pElements = pDest->elements;
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ _copyConstructStruct(
+ pElements + (nPos * nElementSize),
+ pSourceElements + (nPos * nElementSize),
+ reinterpret_cast<typelib_CompoundTypeDescription *>(
+ pElementTypeDescr),
+ acquire, mapping );
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE: // sequence of sequence
+ {
+ // coverity[suspicious_sizeof] - sizeof(uno_Sequence*) is correct here
+ pDest = allocSeq( sizeof (uno_Sequence *), nElements );
+ if (pDest != nullptr)
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ typelib_TypeDescriptionReference * pSeqElementType =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(
+ pElementTypeDescr)->pType;
+
+ uno_Sequence ** pDestElements =
+ reinterpret_cast<uno_Sequence **>(pDest->elements);
+ uno_Sequence ** pSourceElements =
+ reinterpret_cast<uno_Sequence **>(pSource->elements);
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ uno_Sequence * pNew = copyConstructSequence(
+ pSourceElements[nPos],
+ pSeqElementType,
+ acquire, mapping );
+ OSL_ASSERT( pNew != nullptr );
+ // ought never be a memory allocation problem,
+ // because of reference counted sequence handles
+ pDestElements[ nPos ] = pNew;
+ }
+
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ pDest = allocSeq( sizeof (void *), nElements );
+ if (pDest != nullptr)
+ {
+ char * pElements = pDest->elements;
+ void ** pSourceElements = reinterpret_cast<void **>(pSource->elements);
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ reinterpret_cast<void **>(pElements)[nPos] = nullptr;
+ if (pSourceElements[nPos])
+ {
+ (*mapping->mapInterface)(
+ mapping, reinterpret_cast<void **>(pElements) + nPos,
+ pSourceElements[nPos],
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ pElementTypeDescr) );
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ }
+ break;
+ }
+ default:
+ OSL_FAIL( "### unexpected sequence element type!" );
+ pDest = nullptr;
+ break;
+ }
+ }
+ else // empty sequence
+ {
+ pDest = allocSeq( 0, 0 );
+ }
+
+ return pDest;
+ }
+}
+
+
+inline void _copyConstructData(
+ void * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ *static_cast<sal_Unicode *>(pDest) = *static_cast<sal_Unicode *>(pSource);
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ *static_cast<sal_Bool *>(pDest) = bool(*static_cast<sal_Bool *>(pSource));
+ break;
+ case typelib_TypeClass_BYTE:
+ *static_cast<sal_Int8 *>(pDest) = *static_cast<sal_Int8 *>(pSource);
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int16 *>(pSource);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int64 *>(pSource);
+ break;
+ case typelib_TypeClass_FLOAT:
+ *static_cast<float *>(pDest) = *static_cast<float *>(pSource);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ *static_cast<double *>(pDest) = *static_cast<double *>(pSource);
+ break;
+ case typelib_TypeClass_STRING:
+ ::rtl_uString_acquire( *static_cast<rtl_uString **>(pSource) );
+ *static_cast<rtl_uString **>(pDest) = *static_cast<rtl_uString **>(pSource);
+ break;
+ case typelib_TypeClass_TYPE:
+ TYPE_ACQUIRE( *static_cast<typelib_TypeDescriptionReference **>(pSource) );
+ *static_cast<typelib_TypeDescriptionReference **>(pDest) = *static_cast<typelib_TypeDescriptionReference **>(pSource);
+ break;
+ case typelib_TypeClass_ANY:
+ _copyConstructAny(
+ static_cast<uno_Any *>(pDest), static_cast<uno_Any *>(pSource)->pData,
+ static_cast<uno_Any *>(pSource)->pType, nullptr,
+ acquire, mapping );
+ break;
+ case typelib_TypeClass_ENUM:
+ *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource);
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (pTypeDescr)
+ {
+ _copyConstructStruct(
+ pDest, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr),
+ acquire, mapping );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ _copyConstructStruct(
+ pDest, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr),
+ acquire, mapping );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ if (mapping)
+ {
+ if (pTypeDescr)
+ {
+ *static_cast<uno_Sequence **>(pDest) = icopyConstructSequence(
+ *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ acquire, mapping );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ *static_cast<uno_Sequence **>(pDest) = icopyConstructSequence(
+ *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ acquire, mapping );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ }
+ else
+ {
+ osl_atomic_increment( &(*static_cast<uno_Sequence **>(pSource))->nRefCount );
+ *static_cast<uno_Sequence **>(pDest) = *static_cast<uno_Sequence **>(pSource);
+ }
+ break;
+ case typelib_TypeClass_INTERFACE:
+ if (mapping)
+ *static_cast<void **>(pDest) = _map( *static_cast<void **>(pSource), pType, pTypeDescr, mapping );
+ else
+ {
+ *static_cast<void **>(pDest) = *static_cast<void **>(pSource);
+ _acquire( *static_cast<void **>(pDest), acquire );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/data.cxx b/cppu/source/uno/data.cxx
new file mode 100644
index 000000000..339e650fe
--- /dev/null
+++ b/cppu/source/uno/data.cxx
@@ -0,0 +1,316 @@
+/* -*- 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/log.hxx>
+#include <uno/data.h>
+
+#include "constr.hxx"
+#include "destr.hxx"
+#include "copy.hxx"
+#include "assign.hxx"
+#include "eq.hxx"
+
+using namespace ::cppu;
+
+namespace cppu
+{
+
+// Sequence<>() (default ctor) relies on this being static:
+uno_Sequence g_emptySeq = { 1, 0, { 0 } };
+typelib_TypeDescriptionReference * g_pVoidType = nullptr;
+
+
+void * binuno_queryInterface( void * pUnoI, typelib_TypeDescriptionReference * pDestType )
+{
+ // init queryInterface() td
+ static typelib_TypeDescription* g_pQITD = []() {
+ typelib_TypeDescriptionReference* type_XInterface
+ = *typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
+ typelib_InterfaceTypeDescription* pTXInterfaceDescr = nullptr;
+ TYPELIB_DANGER_GET(reinterpret_cast<typelib_TypeDescription**>(&pTXInterfaceDescr),
+ type_XInterface);
+ assert(pTXInterfaceDescr->ppAllMembers);
+ typelib_TypeDescription* pQITD = nullptr;
+ typelib_typedescriptionreference_getDescription(&pQITD,
+ pTXInterfaceDescr->ppAllMembers[0]);
+ // coverity[callee_ptr_arith] - not a bug
+ TYPELIB_DANGER_RELEASE(&pTXInterfaceDescr->aBase);
+ return pQITD;
+ }();
+
+ uno_Any aRet, aExc;
+ uno_Any * pExc = &aExc;
+ void * aArgs[ 1 ];
+ aArgs[ 0 ] = &pDestType;
+ (*static_cast<uno_Interface *>(pUnoI)->pDispatcher)(
+ static_cast<uno_Interface *>(pUnoI), g_pQITD, &aRet, aArgs, &pExc );
+
+ uno_Interface * ret = nullptr;
+ if (nullptr == pExc)
+ {
+ typelib_TypeDescriptionReference * ret_type = aRet.pType;
+ switch (ret_type->eTypeClass)
+ {
+ case typelib_TypeClass_VOID: // common case
+ typelib_typedescriptionreference_release( ret_type );
+ break;
+ case typelib_TypeClass_INTERFACE:
+ // tweaky... avoiding acquire/ release pair
+ typelib_typedescriptionreference_release( ret_type );
+ ret = static_cast<uno_Interface *>(aRet.pReserved); // serving acquired interface
+ break;
+ default:
+ _destructAny( &aRet, nullptr );
+ break;
+ }
+ }
+ else
+ {
+ SAL_WARN(
+ "cppu",
+ "exception occurred querying for interface "
+ << OUString(pDestType->pTypeName) << ": ["
+ << OUString(pExc->pType->pTypeName) << "] "
+ << *static_cast<OUString const *>(pExc->pData));
+ // Message is very first member
+ uno_any_destruct( pExc, nullptr );
+ }
+ return ret;
+}
+
+
+void defaultConstructStruct(
+ void * pMem,
+ typelib_CompoundTypeDescription * pCompType )
+{
+ _defaultConstructStruct( pMem, pCompType );
+}
+
+void copyConstructStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ _copyConstructStruct( pDest, pSource, pTypeDescr, acquire, mapping );
+}
+
+void destructStruct(
+ void * pValue,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ _destructStruct( pValue, pTypeDescr, release );
+}
+
+bool equalStruct(
+ void * pDest, void *pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ return _equalStruct( pDest, pSource, pTypeDescr, queryInterface, release );
+}
+
+bool assignStruct(
+ void * pDest, void * pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+{
+ return _assignStruct( pDest, pSource, pTypeDescr, queryInterface, acquire, release );
+}
+
+
+uno_Sequence * copyConstructSequence(
+ uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_AcquireFunc acquire, uno_Mapping * mapping )
+{
+ return icopyConstructSequence( pSource, pElementType, acquire, mapping );
+}
+
+
+void destructSequence(
+ uno_Sequence * pSequence,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ idestructSequence( pSequence, pType, pTypeDescr, release );
+}
+
+
+bool equalSequence(
+ uno_Sequence * pDest, uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ return _equalSequence( pDest, pSource, pElementType, queryInterface, release );
+}
+
+}
+
+extern "C"
+{
+
+void SAL_CALL uno_type_constructData(
+ void * pMem, typelib_TypeDescriptionReference * pType )
+ SAL_THROW_EXTERN_C()
+{
+ _defaultConstructData( pMem, pType, nullptr );
+}
+
+void SAL_CALL uno_constructData(
+ void * pMem, typelib_TypeDescription * pTypeDescr )
+ SAL_THROW_EXTERN_C()
+{
+ _defaultConstructData( pMem, pTypeDescr->pWeakRef, pTypeDescr );
+}
+
+void SAL_CALL uno_type_destructData(
+ void * pValue, typelib_TypeDescriptionReference * pType,
+ uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructData( pValue, pType, nullptr, release );
+}
+
+void SAL_CALL uno_destructData(
+ void * pValue,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ _destructData( pValue, pTypeDescr->pWeakRef, pTypeDescr, release );
+}
+
+void SAL_CALL uno_type_copyData(
+ void * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ _copyConstructData( pDest, pSource, pType, nullptr, acquire, nullptr );
+}
+
+void SAL_CALL uno_copyData(
+ void * pDest, void * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ _copyConstructData( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr );
+}
+
+void SAL_CALL uno_type_copyAndConvertData(
+ void * pDest, void * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ _copyConstructData( pDest, pSource, pType, nullptr, nullptr, mapping );
+}
+
+void SAL_CALL uno_copyAndConvertData(
+ void * pDest, void * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_Mapping * mapping )
+ SAL_THROW_EXTERN_C()
+{
+ _copyConstructData( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, nullptr, mapping );
+}
+
+sal_Bool SAL_CALL uno_type_equalData(
+ void * pVal1, typelib_TypeDescriptionReference * pVal1Type,
+ void * pVal2, typelib_TypeDescriptionReference * pVal2Type,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ return _equalData(
+ pVal1, pVal1Type, nullptr,
+ pVal2, pVal2Type,
+ queryInterface, release );
+}
+
+sal_Bool SAL_CALL uno_equalData(
+ void * pVal1, typelib_TypeDescription * pVal1TD,
+ void * pVal2, typelib_TypeDescription * pVal2TD,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ return _equalData(
+ pVal1, pVal1TD->pWeakRef, pVal1TD,
+ pVal2, pVal2TD->pWeakRef,
+ queryInterface, release );
+}
+
+sal_Bool SAL_CALL uno_type_assignData(
+ void * pDest, typelib_TypeDescriptionReference * pDestType,
+ void * pSource, typelib_TypeDescriptionReference * pSourceType,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ return _assignData(
+ pDest, pDestType, nullptr,
+ pSource, pSourceType, nullptr,
+ queryInterface, acquire, release );
+}
+
+sal_Bool SAL_CALL uno_assignData(
+ void * pDest, typelib_TypeDescription * pDestTD,
+ void * pSource, typelib_TypeDescription * pSourceTD,
+ uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ return _assignData(
+ pDest, pDestTD->pWeakRef, pDestTD,
+ pSource, pSourceTD->pWeakRef, pSourceTD,
+ queryInterface, acquire, release );
+}
+
+sal_Bool SAL_CALL uno_type_isAssignableFromData(
+ typelib_TypeDescriptionReference * pAssignable,
+ void * pFrom, typelib_TypeDescriptionReference * pFromType,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ if (::typelib_typedescriptionreference_isAssignableFrom( pAssignable, pFromType ))
+ return true;
+ if (typelib_TypeClass_INTERFACE != pFromType->eTypeClass ||
+ typelib_TypeClass_INTERFACE != pAssignable->eTypeClass)
+ {
+ return false;
+ }
+
+ // query
+ if (nullptr == pFrom)
+ return false;
+ void * pInterface = *static_cast<void **>(pFrom);
+ if (nullptr == pInterface)
+ return false;
+
+ if (nullptr == queryInterface)
+ queryInterface = binuno_queryInterface;
+ void * p = (*queryInterface)( pInterface, pAssignable );
+ _release( p, release );
+ return (nullptr != p);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/destr.hxx b/cppu/source/uno/destr.hxx
new file mode 100644
index 000000000..13e4ca044
--- /dev/null
+++ b/cppu/source/uno/destr.hxx
@@ -0,0 +1,352 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/config.h>
+#include <osl/diagnose.h>
+
+#include <cassert>
+#include <cstdlib>
+
+#include "prim.hxx"
+
+namespace cppu
+{
+
+
+//#### destruction #################################################################################
+
+
+void destructStruct(
+ void * pValue,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_ReleaseFunc release );
+
+inline void _destructStruct(
+ void * pValue,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ destructStruct( pValue, pTypeDescr->pBaseTypeDescription, release );
+ }
+
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+ while (nDescr--)
+ {
+ ::uno_type_destructData(
+ static_cast<char *>(pValue) + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr], release );
+ }
+}
+
+
+void destructSequence(
+ uno_Sequence * pSequence,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release );
+
+
+inline void _destructAny(
+ uno_Any * pAny,
+ uno_ReleaseFunc release )
+{
+ typelib_TypeDescriptionReference * pType = pAny->pType;
+
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (sizeof(void *) < sizeof(sal_Int64))
+ {
+ std::free( pAny->pData );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (sizeof(void *) < sizeof(float))
+ {
+ std::free( pAny->pData );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (sizeof(void *) < sizeof(double))
+ {
+ std::free( pAny->pData );
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ ::rtl_uString_release( static_cast<rtl_uString *>(pAny->pReserved) );
+ break;
+ case typelib_TypeClass_TYPE:
+ ::typelib_typedescriptionreference_release(
+ static_cast<typelib_TypeDescriptionReference *>(pAny->pReserved) );
+ break;
+ case typelib_TypeClass_ANY:
+ OSL_FAIL( "### unexpected nested any!" );
+ ::uno_any_destruct( static_cast<uno_Any *>(pAny->pData), release );
+ std::free( pAny->pData );
+ break;
+ case typelib_TypeClass_TYPEDEF:
+ OSL_FAIL( "### unexpected typedef!" );
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ _destructStruct( pAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ std::free( pAny->pData );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ destructSequence(
+ static_cast<uno_Sequence *>(pAny->pReserved), pType, nullptr, release );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ _release( pAny->pReserved, release );
+ break;
+ default:
+ break;
+ }
+#if OSL_DEBUG_LEVEL > 0
+ pAny->pData = reinterpret_cast<void *>(uintptr_t(0xdeadbeef));
+#endif
+
+ ::typelib_typedescriptionreference_release( pType );
+}
+
+inline sal_Int32 idestructElements(
+ void * pElements, typelib_TypeDescriptionReference * pElementType,
+ sal_Int32 nStartIndex, sal_Int32 nStopIndex,
+ uno_ReleaseFunc release )
+{
+ switch (pElementType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ return sal_Int32(sizeof(sal_Unicode));
+ case typelib_TypeClass_BOOLEAN:
+ return sal_Int32(sizeof(sal_Bool));
+ case typelib_TypeClass_BYTE:
+ return sal_Int32(sizeof(sal_Int8));
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return sal_Int32(sizeof(sal_Int16));
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return sal_Int32(sizeof(sal_Int32));
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return sal_Int32(sizeof(sal_Int64));
+ case typelib_TypeClass_FLOAT:
+ return sal_Int32(sizeof(float));
+ case typelib_TypeClass_DOUBLE:
+ return sal_Int32(sizeof(double));
+
+ case typelib_TypeClass_STRING:
+ {
+ rtl_uString ** pDest = static_cast<rtl_uString **>(pElements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ ::rtl_uString_release( pDest[nPos] );
+ }
+ return sal_Int32(sizeof(rtl_uString *));
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ typelib_TypeDescriptionReference ** pDest = static_cast<typelib_TypeDescriptionReference **>(pElements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ ::typelib_typedescriptionreference_release( pDest[nPos] );
+ }
+ return sal_Int32(sizeof(typelib_TypeDescriptionReference *));
+ }
+ case typelib_TypeClass_ANY:
+ {
+ uno_Any * pDest = static_cast<uno_Any *>(pElements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ _destructAny( &pDest[nPos], release );
+ }
+ return sal_Int32(sizeof(uno_Any));
+ }
+ case typelib_TypeClass_ENUM:
+ return sal_Int32(sizeof(sal_Int32));
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 nElementSize = pElementTypeDescr->nSize;
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ _destructStruct(
+ static_cast<char *>(pElements) + (nElementSize * nPos),
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr),
+ release );
+ }
+ sal_Int32 nSize = pElementTypeDescr->nSize;
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return nSize;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ uno_Sequence ** pDest = static_cast<uno_Sequence **>(pElements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ destructSequence(
+ pDest[nPos],
+ pElementTypeDescr->pWeakRef, pElementTypeDescr,
+ release );
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return sal_Int32(sizeof(uno_Sequence *));
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ if (release)
+ {
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ void * p = static_cast<void **>(pElements)[nPos];
+ if (p)
+ {
+ (*release)( p );
+ }
+ }
+ }
+ else
+ {
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ uno_Interface * p = static_cast<uno_Interface **>(pElements)[nPos];
+ if (p)
+ {
+ (*p->release)( p );
+ }
+ }
+ }
+ return sal_Int32(sizeof(void *));
+ }
+ default:
+ OSL_ASSERT(false);
+ return 0;
+ }
+}
+
+inline void idestroySequence(
+ uno_Sequence * pSeq,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ assert(pSeq != nullptr);
+ assert(pSeq->nRefCount == 0);
+ if (pSeq->nElements > 0)
+ {
+ if (pTypeDescr)
+ {
+ idestructElements(
+ pSeq->elements,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, 0,
+ pSeq->nElements, release );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ idestructElements(
+ pSeq->elements,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, 0,
+ pSeq->nElements, release );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ }
+ std::free( pSeq );
+}
+
+inline void idestructSequence(
+ uno_Sequence * pSeq,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ if (osl_atomic_decrement( &pSeq->nRefCount ) == 0)
+ {
+ idestroySequence(pSeq, pType, pTypeDescr, release);
+ }
+}
+
+inline void _destructData(
+ void * pValue,
+ typelib_TypeDescriptionReference * pType,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+{
+ switch (pType->eTypeClass)
+ {
+ case typelib_TypeClass_STRING:
+ ::rtl_uString_release( *static_cast<rtl_uString **>(pValue) );
+ break;
+ case typelib_TypeClass_TYPE:
+ ::typelib_typedescriptionreference_release( *static_cast<typelib_TypeDescriptionReference **>(pValue) );
+ break;
+ case typelib_TypeClass_ANY:
+ _destructAny( static_cast<uno_Any *>(pValue), release );
+ break;
+ case typelib_TypeClass_TYPEDEF:
+ OSL_FAIL( "### unexpected typedef!" );
+ break;
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (pTypeDescr)
+ {
+ _destructStruct( pValue, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ _destructStruct( pValue, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ break;
+ case typelib_TypeClass_SEQUENCE:
+ {
+ idestructSequence(
+ *static_cast<uno_Sequence **>(pValue), pType, pTypeDescr, release );
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ _release( *static_cast<void **>(pValue), release );
+ break;
+ default:
+ break;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/eq.hxx b/cppu/source/uno/eq.hxx
new file mode 100644
index 000000000..60a372886
--- /dev/null
+++ b/cppu/source/uno/eq.hxx
@@ -0,0 +1,635 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <cmath>
+#include <string.h>
+
+#include <o3tl/intcmp.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+
+#include "prim.hxx"
+
+
+namespace cppu
+{
+
+
+//#### equality ####################################################################################
+
+
+inline bool _equalObject(
+ void * pI1, void * pI2,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ if (pI1 == pI2)
+ return true;
+ if ((nullptr == pI1) || (nullptr == pI2))
+ return false;
+ bool bRet = false;
+
+ typelib_TypeDescriptionReference * type_XInterface =
+ * typelib_static_type_getByTypeClass( typelib_TypeClass_INTERFACE );
+ if (nullptr == queryInterface)
+ queryInterface = binuno_queryInterface;
+ pI1 = (*queryInterface)( pI1, type_XInterface );
+ if (nullptr != pI1)
+ {
+ pI2 = (*queryInterface)( pI2, type_XInterface );
+ if (nullptr != pI2)
+ {
+ bRet = (pI1 == pI2);
+ _release( pI2, release );
+ }
+ _release( pI1, release );
+ }
+ return bRet;
+}
+
+
+bool equalStruct(
+ void * pDest, void *pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release );
+
+inline bool _equalStruct(
+ void * pDest, void *pSource,
+ typelib_CompoundTypeDescription * pTypeDescr,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ if (pTypeDescr->pBaseTypeDescription &&
+ !equalStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, queryInterface, release ))
+ {
+ return false;
+ }
+
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+
+ while (nDescr--)
+ {
+ sal_Int32 nOffset = pMemberOffsets[nDescr];
+ if (! ::uno_type_equalData( static_cast<char *>(pDest) + nOffset,
+ ppTypeRefs[nDescr],
+ static_cast<char *>(pSource) + nOffset,
+ ppTypeRefs[nDescr],
+ queryInterface, release ))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool equalSequence(
+ uno_Sequence * pDest, uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release );
+
+inline bool _equalSequence(
+ uno_Sequence * pDest, uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pElementType,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ if (pDest == pSource)
+ return true;
+ sal_Int32 nElements = pDest->nElements;
+ if (nElements != pSource->nElements)
+ return false;
+ if (! nElements)
+ return true;
+
+ void * pDestElements = pDest->elements;
+ void * pSourceElements = pSource->elements;
+
+ switch (pElementType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Unicode) * nElements ));
+ case typelib_TypeClass_BOOLEAN:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (bool(static_cast<sal_Bool *>(pDestElements)[nPos]) !=
+ bool(static_cast<sal_Bool *>(pSourceElements)[nPos]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ case typelib_TypeClass_BYTE:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int8) * nElements ));
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int16) * nElements ));
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int32) * nElements ));
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int64) * nElements ));
+ case typelib_TypeClass_FLOAT:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (static_cast<float *>(pDestElements)[nPos] != static_cast<float *>(pSourceElements)[nPos])
+ return false;
+ }
+ return true;
+ }
+ case typelib_TypeClass_DOUBLE:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (static_cast<double *>(pDestElements)[nPos] != static_cast<double *>(pSourceElements)[nPos])
+ return false;
+ }
+ return true;
+ }
+ case typelib_TypeClass_STRING:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if ( static_cast<OUString *>(pDestElements)[nPos] != static_cast<const OUString *>(pSourceElements)[nPos] )
+ return false;
+ }
+ return true;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (! _type_equals( static_cast<typelib_TypeDescriptionReference **>(pDestElements)[nPos],
+ static_cast<typelib_TypeDescriptionReference **>(pSourceElements)[nPos] ))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ uno_Any * pDest2 = static_cast<uno_Any *>(pDestElements) + nPos;
+ uno_Any * pSource2 = static_cast<uno_Any *>(pSourceElements) + nPos;
+ if (! ::uno_type_equalData( pDest2->pData, pDest2->pType,
+ pSource2->pData, pSource2->pType,
+ queryInterface, release ))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ case typelib_TypeClass_ENUM:
+ return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int32) * nElements ));
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 nElementSize = pElementTypeDescr->nSize;
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (! _equalStruct( static_cast<char *>(pDestElements) + (nPos * nElementSize),
+ static_cast<char *>(pSourceElements) + (nPos * nElementSize),
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr),
+ queryInterface, release ))
+ {
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return false;
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return true;
+ }
+ case typelib_TypeClass_SEQUENCE: // sequence of sequence
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ typelib_TypeDescriptionReference * pSeqElementType =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pElementTypeDescr)->pType;
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (! equalSequence( static_cast<uno_Sequence **>(pDestElements)[nPos],
+ static_cast<uno_Sequence **>(pSourceElements)[nPos],
+ pSeqElementType, queryInterface, release ))
+ {
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return false;
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ return true;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ for ( sal_Int32 nPos = nElements; nPos--; )
+ {
+ if (! _equalObject( static_cast<void **>(pDestElements)[nPos], static_cast<void **>(pSourceElements)[nPos],
+ queryInterface, release ))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ default:
+ OSL_ASSERT(false);
+ return false;
+ }
+}
+
+inline bool _equalData(
+ void * pDest,
+ typelib_TypeDescriptionReference * pDestType, typelib_TypeDescription * pDestTypeDescr,
+ void * pSource,
+ typelib_TypeDescriptionReference * pSourceType,
+ uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release )
+{
+ typelib_TypeClass eSourceTypeClass, eDestTypeClass;
+ while (typelib_TypeClass_ANY == (eDestTypeClass = pDestType->eTypeClass))
+ {
+ pDestTypeDescr = nullptr;
+ pDestType = static_cast<uno_Any *>(pDest)->pType;
+ pDest = static_cast<uno_Any *>(pDest)->pData;
+ }
+ while (typelib_TypeClass_ANY == (eSourceTypeClass = pSourceType->eTypeClass))
+ {
+ pSourceType = static_cast<uno_Any *>(pSource)->pType;
+ pSource = static_cast<uno_Any *>(pSource)->pData;
+ }
+
+ switch (eDestTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ return eSourceTypeClass == typelib_TypeClass_VOID;
+ case typelib_TypeClass_CHAR:
+ return eSourceTypeClass == typelib_TypeClass_CHAR
+ && *static_cast<sal_Unicode *>(pDest) == *static_cast<sal_Unicode *>(pSource);
+ case typelib_TypeClass_BOOLEAN:
+ return eSourceTypeClass == typelib_TypeClass_BOOLEAN
+ && (bool(*static_cast<sal_Bool *>(pDest))
+ == bool(*static_cast<sal_Bool *>(pSource)));
+ case typelib_TypeClass_BYTE:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int8 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_SHORT:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int16 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt16 *>(pDest), *static_cast<sal_uInt64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_LONG:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int32 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_LONG:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt32 *>(pDest), *static_cast<sal_uInt64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_HYPER:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_Int64 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (static_cast<float>(*static_cast<sal_Int64 *>(pDest)) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<sal_Int64 *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_Int8 *>(pSource));
+ case typelib_TypeClass_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_Int16 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_uInt16 *>(pSource));
+ case typelib_TypeClass_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_uInt32 *>(pSource));
+ case typelib_TypeClass_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_Int64 *>(pSource));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ return o3tl::cmp_equal(
+ *static_cast<sal_uInt64 *>(pDest), *static_cast<sal_uInt64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ if (::floor( *static_cast<float *>(pSource) ) != *static_cast<float *>(pSource) || *static_cast<float *>(pSource) < 0)
+ return false;
+ return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<float *>(pSource)));
+ case typelib_TypeClass_DOUBLE:
+ if (::floor( *static_cast<double *>(pSource) ) != *static_cast<double *>(pSource) || *static_cast<double *>(pSource) < 0)
+ return false;
+ return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<double *>(pSource)));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_FLOAT:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int8 *>(pSource)));
+ case typelib_TypeClass_SHORT:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int16 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_uInt16 *>(pSource)));
+ case typelib_TypeClass_LONG:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int32 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_uInt32 *>(pSource)));
+ case typelib_TypeClass_HYPER:
+ return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int64 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (::floor( *static_cast<float *>(pDest) ) != *static_cast<float *>(pDest) || *static_cast<float *>(pDest) < 0)
+ return false;
+ return (static_cast<sal_uInt64>(*static_cast<float *>(pDest)) == *static_cast<sal_uInt64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (*static_cast<float *>(pDest) == *static_cast<float *>(pSource));
+ case typelib_TypeClass_DOUBLE:
+ return (static_cast<double>(*static_cast<float *>(pDest)) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_DOUBLE:
+ switch (eSourceTypeClass)
+ {
+ case typelib_TypeClass_BYTE:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int8 *>(pSource)));
+ case typelib_TypeClass_SHORT:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int16 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_uInt16 *>(pSource)));
+ case typelib_TypeClass_LONG:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int32 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_LONG:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_uInt32 *>(pSource)));
+ case typelib_TypeClass_HYPER:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int64 *>(pSource)));
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (::floor( *static_cast<double *>(pDest) ) != *static_cast<double *>(pDest) || *static_cast<double *>(pDest) < 0)
+ return false;
+ return (static_cast<sal_uInt64>(*static_cast<double *>(pDest)) == *static_cast<sal_uInt64 *>(pSource));
+ case typelib_TypeClass_FLOAT:
+ return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<float *>(pSource)));
+ case typelib_TypeClass_DOUBLE:
+ return (*static_cast<double *>(pDest) == *static_cast<double *>(pSource));
+ default:
+ return false;
+ }
+ case typelib_TypeClass_STRING:
+ return eSourceTypeClass == typelib_TypeClass_STRING
+ && *static_cast<OUString *>(pDest) ==
+ *static_cast<OUString const *>(pSource);
+ case typelib_TypeClass_TYPE:
+ return eSourceTypeClass == typelib_TypeClass_TYPE
+ && _type_equals(
+ *static_cast<typelib_TypeDescriptionReference **>(pDest),
+ *static_cast<typelib_TypeDescriptionReference **>(pSource) );
+ case typelib_TypeClass_ENUM:
+ return (_type_equals( pDestType, pSourceType ) &&
+ *static_cast<sal_Int32 *>(pDest) == *static_cast<sal_Int32 *>(pSource));
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ if (! _type_equals( pDestType, pSourceType ))
+ return false;
+ if (pDestTypeDescr)
+ {
+ return _equalStruct(
+ pDest, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pDestTypeDescr),
+ queryInterface, release );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType );
+ bool bRet = _equalStruct(
+ pDest, pSource,
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pDestTypeDescr),
+ queryInterface, release );
+ TYPELIB_DANGER_RELEASE( pDestTypeDescr );
+ return bRet;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ if (_type_equals( pDestType, pSourceType ))
+ {
+ if (pDestTypeDescr)
+ {
+ return _equalSequence(
+ *static_cast<uno_Sequence **>(pDest), *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pDestTypeDescr)->pType,
+ queryInterface, release );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType );
+ bool bRet = _equalSequence(
+ *static_cast<uno_Sequence **>(pDest), *static_cast<uno_Sequence **>(pSource),
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pDestTypeDescr)->pType,
+ queryInterface, release );
+ TYPELIB_DANGER_RELEASE( pDestTypeDescr );
+ return bRet;
+ }
+ }
+ return false;
+ case typelib_TypeClass_INTERFACE:
+ if (typelib_TypeClass_INTERFACE == eSourceTypeClass)
+ return _equalObject( *static_cast<void **>(pDest), *static_cast<void **>(pSource), queryInterface, release );
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+ return false;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/lbenv.cxx b/cppu/source/uno/lbenv.cxx
new file mode 100644
index 000000000..dd29951a6
--- /dev/null
+++ b/cppu/source/uno/lbenv.cxx
@@ -0,0 +1,1147 @@
+/* -*- 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 .
+ */
+
+#ifdef DISABLE_DYNLOADING
+#include <config_java.h>
+#endif
+
+#include <cppu/EnvDcp.hxx>
+
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include <osl/module.hxx>
+#include <osl/process.h>
+#include <rtl/process.h>
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <typelib/typedescription.h>
+#include <uno/dispatcher.h>
+#include <uno/environment.h>
+#include <uno/lbnames.h>
+#include "prim.hxx"
+#include "loadmodule.hxx"
+
+#include <string_view>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <stdio.h>
+
+
+namespace
+{
+
+
+bool td_equals( typelib_InterfaceTypeDescription const * pTD1,
+ typelib_InterfaceTypeDescription const * pTD2 )
+{
+ return (pTD1 == pTD2 ||
+ (pTD1->aBase.pTypeName->length == pTD2->aBase.pTypeName->length &&
+ ::rtl_ustr_compare(
+ pTD1->aBase.pTypeName->buffer,
+ pTD2->aBase.pTypeName->buffer ) == 0));
+}
+
+struct uno_DefaultEnvironment;
+
+
+struct InterfaceEntry
+{
+ sal_Int32 refCount;
+ void * pInterface;
+ uno_freeProxyFunc fpFreeProxy;
+ typelib_InterfaceTypeDescription * pTypeDescr;
+};
+
+struct ObjectEntry
+{
+ OUString oid;
+ std::vector< InterfaceEntry > aInterfaces;
+ sal_Int32 nRef;
+ bool mixedObject;
+
+ explicit ObjectEntry( OUString aOId_ );
+
+ void append(
+ uno_DefaultEnvironment * pEnv,
+ void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
+ uno_freeProxyFunc fpFreeProxy );
+ InterfaceEntry * find(
+ typelib_InterfaceTypeDescription * pTypeDescr );
+ sal_Int32 find( void const * iface_ptr, std::size_t pos ) const;
+};
+
+
+struct FctPtrHash
+{
+ std::size_t operator () ( const void * pKey ) const
+ { return reinterpret_cast< std::size_t>( pKey ); }
+};
+
+
+// mapping from environment name to environment
+typedef std::unordered_map<
+ OUString, uno_Environment * > OUString2EnvironmentMap;
+
+// mapping from ptr to object entry
+typedef std::unordered_map<
+ void *, ObjectEntry *, FctPtrHash > Ptr2ObjectMap;
+// mapping from oid to object entry
+typedef std::unordered_map<
+ OUString, ObjectEntry * > OId2ObjectMap;
+
+struct EnvironmentsData
+{
+ ::osl::Mutex mutex;
+ OUString2EnvironmentMap aName2EnvMap;
+
+ EnvironmentsData() : isDisposing(false) {}
+ ~EnvironmentsData();
+
+ void getEnvironment(
+ uno_Environment ** ppEnv, std::u16string_view rEnvDcp, void * pContext );
+ void registerEnvironment( uno_Environment ** ppEnv );
+ void getRegisteredEnvironments(
+ uno_Environment *** pppEnvs, sal_Int32 * pnLen,
+ uno_memAlloc memAlloc, std::u16string_view rEnvDcp );
+
+ bool isDisposing;
+};
+
+EnvironmentsData& theEnvironmentsData()
+{
+ static EnvironmentsData SINGLETON;
+ return SINGLETON;
+}
+
+struct uno_DefaultEnvironment : public uno_ExtEnvironment
+{
+ sal_Int32 nRef;
+ sal_Int32 nWeakRef;
+
+ ::osl::Mutex mutex;
+ Ptr2ObjectMap aPtr2ObjectMap;
+ OId2ObjectMap aOId2ObjectMap;
+
+ uno_DefaultEnvironment(
+ const OUString & rEnvDcp_, void * pContext_ );
+ ~uno_DefaultEnvironment();
+};
+
+
+ObjectEntry::ObjectEntry( OUString aOId_ )
+ : oid(std::move( aOId_ )),
+ nRef( 0 ),
+ mixedObject( false )
+{
+ aInterfaces.reserve( 2 );
+}
+
+
+void ObjectEntry::append(
+ uno_DefaultEnvironment * pEnv,
+ void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
+ uno_freeProxyFunc fpFreeProxy )
+{
+ InterfaceEntry aNewEntry;
+ if (! fpFreeProxy)
+ (*pEnv->acquireInterface)( pEnv, pInterface );
+ aNewEntry.refCount = 1;
+ aNewEntry.pInterface = pInterface;
+ aNewEntry.fpFreeProxy = fpFreeProxy;
+ typelib_typedescription_acquire( &pTypeDescr->aBase );
+ aNewEntry.pTypeDescr = pTypeDescr;
+
+ std::pair< Ptr2ObjectMap::iterator, bool > i(
+ pEnv->aPtr2ObjectMap.emplace( pInterface, this ) );
+ SAL_WARN_IF(
+ !i.second && (find(pInterface, 0) == -1 || i.first->second != this),
+ "cppu",
+ "map already contains " << i.first->second << " != " << this << " for "
+ << pInterface);
+ aInterfaces.push_back( aNewEntry );
+}
+
+
+InterfaceEntry * ObjectEntry::find(
+ typelib_InterfaceTypeDescription * pTypeDescr_ )
+{
+ OSL_ASSERT( ! aInterfaces.empty() );
+ if (aInterfaces.empty())
+ return nullptr;
+
+ // shortcut common case:
+ OUString const & type_name =
+ OUString::unacquired( &pTypeDescr_->aBase.pTypeName );
+ if ( type_name == "com.sun.star.uno.XInterface" )
+ {
+ return aInterfaces.data();
+ }
+
+ std::size_t nSize = aInterfaces.size();
+ for ( std::size_t nPos = 0; nPos < nSize; ++nPos )
+ {
+ typelib_InterfaceTypeDescription * pITD =
+ aInterfaces[ nPos ].pTypeDescr;
+ while (pITD)
+ {
+ if (td_equals( pITD, pTypeDescr_ ))
+ return &aInterfaces[ nPos ];
+ pITD = pITD->pBaseTypeDescription;
+ }
+ }
+ return nullptr;
+}
+
+
+sal_Int32 ObjectEntry::find(
+ void const * iface_ptr, std::size_t pos ) const
+{
+ std::size_t size = aInterfaces.size();
+ for ( ; pos < size; ++pos )
+ {
+ if (aInterfaces[ pos ].pInterface == iface_ptr)
+ return pos;
+ }
+ return -1;
+}
+
+extern "C"
+{
+
+
+static void defenv_registerInterface(
+ uno_ExtEnvironment * pEnv, void ** ppInterface,
+ rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
+{
+ OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" );
+ OUString const & rOId = OUString::unacquired( &pOId );
+
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::ClearableMutexGuard guard( that->mutex );
+
+ // try to insert dummy 0:
+ std::pair<OId2ObjectMap::iterator, bool> const insertion(
+ that->aOId2ObjectMap.emplace( rOId, nullptr ) );
+ if (insertion.second)
+ {
+ ObjectEntry * pOEntry = new ObjectEntry( rOId );
+ insertion.first->second = pOEntry;
+ ++pOEntry->nRef; // another register call on object
+ pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
+ }
+ else // object entry exists
+ {
+ ObjectEntry * pOEntry = insertion.first->second;
+ ++pOEntry->nRef; // another register call on object
+ InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
+
+ if (pIEntry) // type entry exists
+ {
+ ++pIEntry->refCount;
+ if (pIEntry->pInterface != *ppInterface)
+ {
+ void * pInterface = pIEntry->pInterface;
+ (*pEnv->acquireInterface)( pEnv, pInterface );
+ guard.clear();
+ (*pEnv->releaseInterface)( pEnv, *ppInterface );
+ *ppInterface = pInterface;
+ }
+ }
+ else
+ {
+ pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
+ }
+ }
+}
+
+
+static void defenv_registerProxyInterface(
+ uno_ExtEnvironment * pEnv, void ** ppInterface, uno_freeProxyFunc freeProxy,
+ rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
+{
+ OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr && freeProxy,
+ "### null ptr!" );
+ OUString const & rOId = OUString::unacquired( &pOId );
+
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::ClearableMutexGuard guard( that->mutex );
+
+ // try to insert dummy 0:
+ std::pair<OId2ObjectMap::iterator, bool> const insertion(
+ that->aOId2ObjectMap.emplace( rOId, nullptr ) );
+ if (insertion.second)
+ {
+ ObjectEntry * pOEntry = new ObjectEntry( rOId );
+ insertion.first->second = pOEntry;
+ ++pOEntry->nRef; // another register call on object
+ pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
+ }
+ else // object entry exists
+ {
+ ObjectEntry * pOEntry = insertion.first->second;
+
+ // first registration was an original, then registerProxyInterface():
+ pOEntry->mixedObject |=
+ (!pOEntry->aInterfaces.empty() &&
+ pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr);
+
+ ++pOEntry->nRef; // another register call on object
+ InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
+
+ if (pIEntry) // type entry exists
+ {
+ if (pIEntry->pInterface == *ppInterface)
+ {
+ ++pIEntry->refCount;
+ }
+ else
+ {
+ void * pInterface = pIEntry->pInterface;
+ (*pEnv->acquireInterface)( pEnv, pInterface );
+ --pOEntry->nRef; // manual revoke of proxy to be freed
+ guard.clear();
+ (*freeProxy)( pEnv, *ppInterface );
+ *ppInterface = pInterface;
+ }
+ }
+ else
+ {
+ pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
+ }
+ }
+}
+
+
+static void s_stub_defenv_revokeInterface(va_list * pParam)
+{
+ uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
+ void * pInterface = va_arg(*pParam, void *);
+
+ OSL_ENSURE( pEnv && pInterface, "### null ptr!" );
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::ClearableMutexGuard guard( that->mutex );
+
+ Ptr2ObjectMap::const_iterator const iFind(
+ that->aPtr2ObjectMap.find( pInterface ) );
+ OSL_ASSERT( iFind != that->aPtr2ObjectMap.end() );
+ ObjectEntry * pOEntry = iFind->second;
+ if (! --pOEntry->nRef)
+ {
+ // cleanup maps
+ that->aOId2ObjectMap.erase( pOEntry->oid );
+ sal_Int32 nPos;
+ for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
+ {
+ that->aPtr2ObjectMap.erase( pOEntry->aInterfaces[nPos].pInterface );
+ }
+
+ // the last proxy interface of the environment might kill this
+ // environment, because of releasing its language binding!!!
+ guard.clear();
+
+ // release interfaces
+ for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
+ {
+ InterfaceEntry const & rEntry = pOEntry->aInterfaces[nPos];
+ typelib_typedescription_release( &rEntry.pTypeDescr->aBase );
+ if (rEntry.fpFreeProxy) // is proxy or used interface?
+ {
+ (*rEntry.fpFreeProxy)( pEnv, rEntry.pInterface );
+ }
+ else
+ {
+ (*pEnv->releaseInterface)( pEnv, rEntry.pInterface );
+ }
+ }
+
+ delete pOEntry;
+ }
+ else if (pOEntry->mixedObject)
+ {
+ OSL_ASSERT( !pOEntry->aInterfaces.empty() &&
+ pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr );
+
+ sal_Int32 index = pOEntry->find( pInterface, 1 );
+ OSL_ASSERT( index > 0 );
+ if (index > 0)
+ {
+ InterfaceEntry & entry = pOEntry->aInterfaces[ index ];
+ OSL_ASSERT( entry.pInterface == pInterface );
+ if (entry.fpFreeProxy != nullptr)
+ {
+ --entry.refCount;
+ if (entry.refCount == 0)
+ {
+ uno_freeProxyFunc fpFreeProxy = entry.fpFreeProxy;
+ typelib_TypeDescription * pTypeDescr =
+ reinterpret_cast< typelib_TypeDescription * >(
+ entry.pTypeDescr );
+
+ pOEntry->aInterfaces.erase(
+ pOEntry->aInterfaces.begin() + index );
+ if (pOEntry->find( pInterface, index ) < 0)
+ {
+ // proxy ptr not registered for another interface:
+ // remove from ptr map
+ std::size_t erased =
+ that->aPtr2ObjectMap.erase( pInterface );
+ OSL_ASSERT( erased == 1 );
+ }
+
+ guard.clear();
+
+ typelib_typedescription_release( pTypeDescr );
+ (*fpFreeProxy)( pEnv, pInterface );
+ }
+ }
+ }
+ }
+}
+
+static void defenv_revokeInterface(uno_ExtEnvironment * pEnv, void * pInterface)
+{
+ uno_Environment_invoke(&pEnv->aBase, s_stub_defenv_revokeInterface, pEnv, pInterface);
+}
+
+
+static void defenv_getObjectIdentifier(
+ uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
+{
+ OSL_ENSURE( pEnv && ppOId && pInterface, "### null ptr!" );
+ if (*ppOId)
+ {
+ ::rtl_uString_release( *ppOId );
+ *ppOId = nullptr;
+ }
+
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::ClearableMutexGuard guard( that->mutex );
+
+ Ptr2ObjectMap::const_iterator const iFind(
+ that->aPtr2ObjectMap.find( pInterface ) );
+ if (iFind == that->aPtr2ObjectMap.end())
+ {
+ guard.clear();
+ (*pEnv->computeObjectIdentifier)( pEnv, ppOId, pInterface );
+ }
+ else
+ {
+ rtl_uString * hstr = iFind->second->oid.pData;
+ rtl_uString_acquire( hstr );
+ *ppOId = hstr;
+ }
+}
+
+
+static void defenv_getRegisteredInterface(
+ uno_ExtEnvironment * pEnv, void ** ppInterface,
+ rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
+{
+ OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" );
+ if (*ppInterface)
+ {
+ (*pEnv->releaseInterface)( pEnv, *ppInterface );
+ *ppInterface = nullptr;
+ }
+
+ OUString const & rOId = OUString::unacquired( &pOId );
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::MutexGuard guard( that->mutex );
+
+ OId2ObjectMap::const_iterator const iFind
+ ( that->aOId2ObjectMap.find( rOId ) );
+ if (iFind != that->aOId2ObjectMap.end())
+ {
+ InterfaceEntry const * pIEntry = iFind->second->find( pTypeDescr );
+ if (pIEntry)
+ {
+ (*pEnv->acquireInterface)( pEnv, pIEntry->pInterface );
+ *ppInterface = pIEntry->pInterface;
+ }
+ }
+}
+
+
+static void defenv_getRegisteredInterfaces(
+ uno_ExtEnvironment * pEnv, void *** pppInterfaces, sal_Int32 * pnLen,
+ uno_memAlloc memAlloc )
+{
+ assert(pEnv && pppInterfaces && pnLen && memAlloc && "### null ptr!");
+ uno_DefaultEnvironment * that =
+ static_cast< uno_DefaultEnvironment * >( pEnv );
+ ::osl::MutexGuard guard( that->mutex );
+
+ sal_Int32 nLen = that->aPtr2ObjectMap.size();
+ sal_Int32 nPos = 0;
+ void ** ppInterfaces = static_cast<void **>((*memAlloc)( nLen * sizeof (void *) ));
+
+ for (const auto& rEntry : that->aPtr2ObjectMap)
+ {
+ ppInterfaces[nPos] = rEntry.first;
+ (*pEnv->acquireInterface)( pEnv, ppInterfaces[nPos] );
+ nPos++;
+ }
+
+ *pppInterfaces = ppInterfaces;
+ *pnLen = nLen;
+}
+
+
+static void defenv_acquire( uno_Environment * pEnv )
+{
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ osl_atomic_increment( &that->nWeakRef );
+ osl_atomic_increment( &that->nRef );
+}
+
+
+static void defenv_release( uno_Environment * pEnv )
+{
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ if (! osl_atomic_decrement( &that->nRef ))
+ {
+ // invoke dispose callback
+ if (pEnv->environmentDisposing)
+ {
+ (*pEnv->environmentDisposing)( pEnv );
+ }
+
+ OSL_ENSURE( that->aOId2ObjectMap.empty(), "### object entries left!" );
+ }
+ // free memory if no weak refs left
+ if (! osl_atomic_decrement( &that->nWeakRef ))
+ {
+ delete that;
+ }
+}
+
+
+static void defenv_acquireWeak( uno_Environment * pEnv )
+{
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ osl_atomic_increment( &that->nWeakRef );
+}
+
+
+static void defenv_releaseWeak( uno_Environment * pEnv )
+{
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ if (! osl_atomic_decrement( &that->nWeakRef ))
+ {
+ delete that;
+ }
+}
+
+
+static void defenv_harden(
+ uno_Environment ** ppHardEnv, uno_Environment * pEnv )
+{
+ if (*ppHardEnv)
+ {
+ (*(*ppHardEnv)->release)( *ppHardEnv );
+ *ppHardEnv = nullptr;
+ }
+
+ EnvironmentsData & rData = theEnvironmentsData();
+
+ if (rData.isDisposing)
+ return;
+
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ {
+ ::osl::MutexGuard guard( rData.mutex );
+ if (1 == osl_atomic_increment( &that->nRef )) // is dead
+ {
+ that->nRef = 0;
+ return;
+ }
+ }
+ osl_atomic_increment( &that->nWeakRef );
+ *ppHardEnv = pEnv;
+}
+
+
+static void defenv_dispose( SAL_UNUSED_PARAMETER uno_Environment * )
+{
+}
+}
+
+
+uno_DefaultEnvironment::uno_DefaultEnvironment(
+ const OUString & rEnvDcp_, void * pContext_ )
+ : nRef( 0 ),
+ nWeakRef( 0 )
+{
+ uno_Environment * that = reinterpret_cast< uno_Environment * >(this);
+ that->pReserved = nullptr;
+ // functions
+ that->acquire = defenv_acquire;
+ that->release = defenv_release;
+ that->acquireWeak = defenv_acquireWeak;
+ that->releaseWeak = defenv_releaseWeak;
+ that->harden = defenv_harden;
+ that->dispose = defenv_dispose;
+ that->pExtEnv = this;
+ // identifier
+ ::rtl_uString_acquire( rEnvDcp_.pData );
+ that->pTypeName = rEnvDcp_.pData;
+ that->pContext = pContext_;
+
+ // will be late initialized
+ that->environmentDisposing = nullptr;
+
+ uno_ExtEnvironment::registerInterface = defenv_registerInterface;
+ uno_ExtEnvironment::registerProxyInterface = defenv_registerProxyInterface;
+ uno_ExtEnvironment::revokeInterface = defenv_revokeInterface;
+ uno_ExtEnvironment::getObjectIdentifier = defenv_getObjectIdentifier;
+ uno_ExtEnvironment::getRegisteredInterface = defenv_getRegisteredInterface;
+ uno_ExtEnvironment::getRegisteredInterfaces =
+ defenv_getRegisteredInterfaces;
+
+}
+
+
+uno_DefaultEnvironment::~uno_DefaultEnvironment()
+{
+ ::rtl_uString_release( aBase.pTypeName );
+}
+
+
+void writeLine(
+ void * stream, const char * pLine, const char * pFilter )
+{
+ if (pFilter && *pFilter)
+ {
+ // lookup pFilter in pLine
+ while (*pLine)
+ {
+ if (*pLine == *pFilter)
+ {
+ sal_Int32 nPos = 1;
+ while (pLine[nPos] && pFilter[nPos] == pLine[nPos])
+ {
+ ++nPos;
+ }
+ if (! pFilter[nPos])
+ {
+ if (stream)
+ {
+ fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
+ }
+ else
+ {
+ SAL_WARN("cppu", pLine );
+ }
+ }
+ }
+ ++pLine;
+ }
+ }
+ else
+ {
+ if (stream)
+ {
+ fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
+ }
+ else
+ {
+ fprintf( stderr, "%s\n", pLine );
+ }
+ }
+}
+
+
+void writeLine(
+ void * stream, std::u16string_view rLine, const char * pFilter )
+{
+ OString aLine( OUStringToOString(
+ rLine, RTL_TEXTENCODING_ASCII_US ) );
+ writeLine( stream, aLine.getStr(), pFilter );
+}
+
+}
+
+extern "C" void SAL_CALL uno_dumpEnvironment(
+ void * stream, uno_Environment * pEnv, const char * pFilter )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( pEnv, "### null ptr!" );
+ OUStringBuffer buf;
+
+ if (! pEnv->pExtEnv)
+ {
+ writeLine( stream, "###################################"
+ "###########################################", pFilter );
+ buf.append( "environment: " );
+ buf.append( pEnv->pTypeName );
+ writeLine( stream, buf.makeStringAndClear(), pFilter );
+ writeLine( stream, "NO INTERFACE INFORMATION AVAILABLE!", pFilter );
+ return;
+ }
+
+ writeLine( stream, "########################################"
+ "######################################", pFilter );
+ buf.append( "environment dump: " );
+ buf.append( pEnv->pTypeName );
+ writeLine( stream, buf.makeStringAndClear(), pFilter );
+
+ uno_DefaultEnvironment * that =
+ reinterpret_cast< uno_DefaultEnvironment * >(pEnv);
+ ::osl::MutexGuard guard( that->mutex );
+
+ Ptr2ObjectMap ptr2obj( that->aPtr2ObjectMap );
+ for (const auto& rEntry : that->aOId2ObjectMap)
+ {
+ ObjectEntry * pOEntry = rEntry.second;
+
+ buf.append( "+ " );
+ if (pOEntry->mixedObject)
+ buf.append( "mixed " );
+ buf.append( "object entry: nRef=" );
+ buf.append( pOEntry->nRef );
+ buf.append( "; oid=\"" );
+ buf.append( pOEntry->oid );
+ buf.append( '\"' );
+ writeLine( stream, buf.makeStringAndClear(), pFilter );
+
+ for ( std::size_t nPos = 0;
+ nPos < pOEntry->aInterfaces.size(); ++nPos )
+ {
+ const InterfaceEntry & rIEntry = pOEntry->aInterfaces[nPos];
+
+ buf.append( " - " );
+ buf.append( rIEntry.pTypeDescr->aBase.pTypeName );
+ if (rIEntry.fpFreeProxy)
+ {
+ buf.append( "; proxy free=0x" );
+ buf.append(
+ reinterpret_cast< sal_IntPtr >(rIEntry.fpFreeProxy), 16 );
+ }
+ else
+ {
+ buf.append( "; original" );
+ }
+ buf.append( "; ptr=0x" );
+ buf.append(
+ reinterpret_cast< sal_IntPtr >(rIEntry.pInterface), 16 );
+
+ if (pOEntry->find( rIEntry.pInterface, nPos + 1 ) < 0)
+ {
+ std::size_t erased = ptr2obj.erase( rIEntry.pInterface );
+ if (erased != 1)
+ {
+ buf.append( " (ptr not found in map!)" );
+ }
+ }
+ writeLine( stream, buf.makeStringAndClear(), pFilter );
+ }
+ }
+ if (! ptr2obj.empty())
+ writeLine( stream, "ptr map inconsistency!!!", pFilter );
+ writeLine( stream, "#####################################"
+ "#########################################", pFilter );
+}
+
+
+extern "C" void SAL_CALL uno_dumpEnvironmentByName(
+ void * stream, rtl_uString * pEnvDcp, const char * pFilter )
+ SAL_THROW_EXTERN_C()
+{
+ uno_Environment * pEnv = nullptr;
+ uno_getEnvironment( &pEnv, pEnvDcp, nullptr );
+ if (pEnv)
+ {
+ ::uno_dumpEnvironment( stream, pEnv, pFilter );
+ (*pEnv->release)( pEnv );
+ }
+ else
+ {
+ writeLine(
+ stream,
+ OUStringConcatenation("environment \"" + OUString::unacquired(&pEnvDcp) + "\" does not exist!"),
+ pFilter );
+ }
+}
+
+namespace
+{
+
+const OUString & unoenv_getStaticOIdPart()
+{
+ static auto const theStaticOIdPart = [] {
+ OUStringBuffer aRet( 64 );
+ aRet.append( "];" );
+ // pid
+ oslProcessInfo info;
+ info.Size = sizeof(oslProcessInfo);
+ if (::osl_getProcessInfo( nullptr, osl_Process_IDENTIFIER, &info ) ==
+ osl_Process_E_None)
+ {
+ aRet.append( static_cast<sal_Int64>(info.Ident), 16 );
+ }
+ else
+ {
+ aRet.append( "unknown process id" );
+ }
+ // good guid
+ sal_uInt8 ar[16];
+ ::rtl_getGlobalProcessId( ar );
+ aRet.append( ';' );
+ for (unsigned char i : ar)
+ aRet.append( static_cast<sal_Int32>(i), 16 );
+
+ return aRet.makeStringAndClear();
+ }();
+ return theStaticOIdPart;
+}
+
+}
+
+extern "C"
+{
+
+
+static void unoenv_computeObjectIdentifier(
+ uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
+{
+ assert(pEnv && ppOId && pInterface && "### null ptr!");
+ if (*ppOId)
+ {
+ ::rtl_uString_release( *ppOId );
+ *ppOId = nullptr;
+ }
+
+ uno_Interface * pUnoI = static_cast<uno_Interface *>(
+ ::cppu::binuno_queryInterface(
+ pInterface, *typelib_static_type_getByTypeClass(
+ typelib_TypeClass_INTERFACE ) ));
+ if (nullptr == pUnoI)
+ return;
+
+ (*pUnoI->release)( pUnoI );
+ OUString aStr(
+ // interface
+ OUString::number( reinterpret_cast< sal_Int64 >(pUnoI), 16 ) + ";"
+ // environment[context]
+ + OUString::unacquired(&pEnv->aBase.pTypeName) + "["
+ + OUString::number( reinterpret_cast< sal_Int64 >(
+ reinterpret_cast<
+ uno_Environment * >(pEnv)->pContext ), 16 )
+ // process;good guid
+ + unoenv_getStaticOIdPart() );
+ *ppOId = aStr.pData;
+ ::rtl_uString_acquire( *ppOId );
+}
+
+
+static void unoenv_acquireInterface(
+ SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
+{
+ uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
+ (*pUnoI->acquire)( pUnoI );
+}
+
+
+static void unoenv_releaseInterface(
+ SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
+{
+ uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
+ (*pUnoI->release)( pUnoI );
+}
+}
+
+namespace {
+
+EnvironmentsData::~EnvironmentsData()
+{
+ ::osl::MutexGuard guard( mutex );
+ isDisposing = true;
+
+ for ( const auto& rEntry : aName2EnvMap )
+ {
+ uno_Environment * pWeak = rEntry.second;
+ uno_Environment * pHard = nullptr;
+ (*pWeak->harden)( &pHard, pWeak );
+ (*pWeak->releaseWeak)( pWeak );
+
+ if (pHard)
+ {
+ (*pHard->dispose)( pHard ); // send explicit dispose
+ (*pHard->release)( pHard );
+ }
+ }
+}
+
+
+void EnvironmentsData::getEnvironment(
+ uno_Environment ** ppEnv, std::u16string_view rEnvDcp, void * pContext )
+{
+ if (*ppEnv)
+ {
+ (*(*ppEnv)->release)( *ppEnv );
+ *ppEnv = nullptr;
+ }
+
+ OUString aKey = OUString::number( reinterpret_cast< sal_IntPtr >(pContext) ) + rEnvDcp;
+
+ // try to find registered mapping
+ OUString2EnvironmentMap::const_iterator const iFind(
+ aName2EnvMap.find( aKey ) );
+ if (iFind != aName2EnvMap.end())
+ {
+ uno_Environment * pWeak = iFind->second;
+ (*pWeak->harden)( ppEnv, pWeak );
+ }
+}
+
+
+void EnvironmentsData::registerEnvironment( uno_Environment ** ppEnv )
+{
+ OSL_ENSURE( ppEnv, "### null ptr!" );
+ uno_Environment * pEnv = *ppEnv;
+
+ OUString aKey =
+ OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->pContext) ) +
+ OUString::unacquired(&pEnv->pTypeName);
+
+ // try to find registered environment
+ OUString2EnvironmentMap::const_iterator const iFind(
+ aName2EnvMap.find( aKey ) );
+ if (iFind == aName2EnvMap.end())
+ {
+ (*pEnv->acquireWeak)( pEnv );
+ std::pair< OUString2EnvironmentMap::iterator, bool > insertion (
+ aName2EnvMap.emplace( aKey, pEnv ) );
+ SAL_WARN_IF( !insertion.second, "cppu", "key " << aKey << " already in env map" );
+ }
+ else
+ {
+ uno_Environment * pHard = nullptr;
+ uno_Environment * pWeak = iFind->second;
+ (*pWeak->harden)( &pHard, pWeak );
+ if (pHard)
+ {
+ (*pEnv->release)( pEnv );
+ *ppEnv = pHard;
+ }
+ else // registered one is dead
+ {
+ (*pWeak->releaseWeak)( pWeak );
+ (*pEnv->acquireWeak)( pEnv );
+ aName2EnvMap[ aKey ] = pEnv;
+ }
+ }
+}
+
+
+void EnvironmentsData::getRegisteredEnvironments(
+ uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
+ std::u16string_view rEnvDcp )
+{
+ assert(pppEnvs && pnLen && memAlloc && "### null ptr!");
+
+ // max size
+ std::vector<uno_Environment*> aFounds(aName2EnvMap.size());
+ sal_Int32 nSize = 0;
+
+ // find matching environment
+ for ( const auto& rEntry : aName2EnvMap )
+ {
+ uno_Environment * pWeak = rEntry.second;
+ if (rEnvDcp.empty() ||
+ rEnvDcp == OUString::unacquired(&pWeak->pTypeName) )
+ {
+ aFounds[nSize] = nullptr;
+ (*pWeak->harden)( &aFounds[nSize], pWeak );
+ if (aFounds[nSize])
+ ++nSize;
+ }
+ }
+
+ *pnLen = nSize;
+ if (nSize)
+ {
+ *pppEnvs = static_cast<uno_Environment **>((*memAlloc)(
+ sizeof (uno_Environment *) * nSize ));
+ OSL_ASSERT( *pppEnvs );
+ while (nSize--)
+ {
+ (*pppEnvs)[nSize] = aFounds[nSize];
+ }
+ }
+ else
+ {
+ *pppEnvs = nullptr;
+ }
+}
+
+bool loadEnv(OUString const & cLibStem,
+ uno_Environment * pEnv)
+{
+#ifdef DISABLE_DYNLOADING
+ uno_initEnvironmentFunc fpInit;
+
+ if ( cLibStem == CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" )
+ fpInit = CPPU_ENV_uno_initEnvironment;
+#if HAVE_FEATURE_JAVA
+ else if ( cLibStem == "java_uno" )
+ fpInit = java_uno_initEnvironment;
+#endif
+ else
+ {
+ SAL_INFO("cppu", ": Unhandled env: " << cLibStem);
+ return false;
+ }
+#else
+ // late init with some code from matching uno language binding
+ // will be unloaded by environment
+ osl::Module aMod;
+ try {
+ bool bMod = cppu::detail::loadModule(aMod, cLibStem);
+ if (!bMod)
+ return false;
+ }
+ catch(...) {
+ // Catch everything and convert to return false
+ return false;
+ }
+
+
+ uno_initEnvironmentFunc fpInit = reinterpret_cast<uno_initEnvironmentFunc>(aMod.getSymbol(UNO_INIT_ENVIRONMENT));
+
+ if (!fpInit)
+ return false;
+
+ aMod.release();
+#endif
+
+ (*fpInit)( pEnv ); // init of environment
+ return true;
+}
+
+}
+
+extern "C"
+{
+
+
+static uno_Environment * initDefaultEnvironment(
+ const OUString & rEnvDcp, void * pContext )
+{
+ // coverity[leaked_storage : FALSE] - lifetime is controlled by acquire()/release() calls
+ uno_Environment * pEnv = &(new uno_DefaultEnvironment( rEnvDcp, pContext ))->aBase;
+ (*pEnv->acquire)( pEnv );
+
+ OUString envTypeName = cppu::EnvDcp::getTypeName(rEnvDcp);
+
+ // create default environment
+ if ( envTypeName == UNO_LB_UNO )
+ {
+ uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
+ that->computeObjectIdentifier = unoenv_computeObjectIdentifier;
+ that->acquireInterface = unoenv_acquireInterface;
+ that->releaseInterface = unoenv_releaseInterface;
+
+ OUString envPurpose = cppu::EnvDcp::getPurpose(rEnvDcp);
+ if (!envPurpose.isEmpty())
+ {
+ OUString libStem(
+ OUString::Concat(envPurpose.subView(envPurpose.lastIndexOf(':') + 1)) + "_uno_uno");
+ if(!loadEnv(libStem, pEnv))
+ {
+ pEnv->release(pEnv);
+ return nullptr;
+ }
+ }
+ }
+ else
+ {
+ // late init with some code from matching uno language binding
+ OUString aStr( envTypeName + "_uno" );
+
+ if (!loadEnv(aStr, pEnv))
+ {
+ pEnv->release(pEnv);
+ return nullptr;
+ }
+ }
+
+ return pEnv;
+}
+
+
+void SAL_CALL uno_createEnvironment(
+ uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppEnv && "### null ptr!");
+ if (*ppEnv)
+ (*(*ppEnv)->release)( *ppEnv );
+
+ OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
+ *ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
+}
+
+void SAL_CALL uno_getEnvironment(
+ uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppEnv && "### null ptr!");
+ OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
+
+ EnvironmentsData & rData = theEnvironmentsData();
+
+ ::osl::MutexGuard guard( rData.mutex );
+ rData.getEnvironment( ppEnv, rEnvDcp, pContext );
+ if (! *ppEnv)
+ {
+ *ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
+ if (*ppEnv)
+ {
+ // register new environment:
+ rData.registerEnvironment( ppEnv );
+ }
+ }
+}
+
+void SAL_CALL uno_getRegisteredEnvironments(
+ uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
+ rtl_uString * pEnvDcp )
+ SAL_THROW_EXTERN_C()
+{
+ EnvironmentsData & rData = theEnvironmentsData();
+
+ ::osl::MutexGuard guard( rData.mutex );
+ rData.getRegisteredEnvironments(
+ pppEnvs, pnLen, memAlloc,
+ (pEnvDcp ? OUString(pEnvDcp) : OUString()) );
+}
+
+} // extern "C"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/lbmap.cxx b/cppu/source/uno/lbmap.cxx
new file mode 100644
index 000000000..b056193de
--- /dev/null
+++ b/cppu/source/uno/lbmap.cxx
@@ -0,0 +1,754 @@
+/* -*- 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 .
+ */
+
+#ifdef DISABLE_DYNLOADING
+#include <config_java.h>
+#endif
+
+#include "IdentityMapping.hxx"
+
+#include <cassert>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+#include <utility>
+
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/module.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <osl/interlck.h>
+#include <sal/log.hxx>
+
+#include <uno/dispatcher.h>
+#include <uno/mapping.h>
+#include <uno/lbnames.h>
+#include <uno/environment.hxx>
+
+#include <typelib/typedescription.h>
+
+#include <cppu/EnvDcp.hxx>
+#include "cascade_mapping.hxx"
+#include "loadmodule.hxx"
+
+using namespace osl;
+using namespace com::sun::star::uno;
+
+namespace cppu
+{
+
+namespace {
+
+class Mapping
+{
+ uno_Mapping * _pMapping;
+
+public:
+ inline explicit Mapping( uno_Mapping * pMapping = nullptr );
+ inline Mapping( const Mapping & rMapping );
+ Mapping(Mapping && other) noexcept : _pMapping(other._pMapping)
+ { other._pMapping = nullptr; }
+ inline ~Mapping();
+ inline Mapping & operator = ( uno_Mapping * pMapping );
+ Mapping & operator = ( const Mapping & rMapping )
+ { return operator = ( rMapping._pMapping ); }
+ Mapping & operator =(Mapping && other) noexcept {
+ if (_pMapping != nullptr) {
+ (*_pMapping->release)(_pMapping);
+ }
+ _pMapping = other._pMapping;
+ other._pMapping = nullptr;
+ return *this;
+ }
+ uno_Mapping * get() const
+ { return _pMapping; }
+ bool is() const
+ { return (_pMapping != nullptr); }
+};
+
+}
+
+inline Mapping::Mapping( uno_Mapping * pMapping )
+ : _pMapping( pMapping )
+{
+ if (_pMapping)
+ (*_pMapping->acquire)( _pMapping );
+}
+
+inline Mapping::Mapping( const Mapping & rMapping )
+ : _pMapping( rMapping._pMapping )
+{
+ if (_pMapping)
+ (*_pMapping->acquire)( _pMapping );
+}
+
+inline Mapping::~Mapping()
+{
+ if (_pMapping)
+ (*_pMapping->release)( _pMapping );
+}
+
+inline Mapping & Mapping::operator = ( uno_Mapping * pMapping )
+{
+ if (pMapping)
+ (*pMapping->acquire)( pMapping );
+ if (_pMapping)
+ (*_pMapping->release)( _pMapping );
+ _pMapping = pMapping;
+ return *this;
+}
+
+namespace {
+
+struct MappingEntry
+{
+ sal_Int32 nRef;
+ uno_Mapping * pMapping;
+ uno_freeMappingFunc freeMapping;
+ OUString aMappingName;
+
+ MappingEntry(
+ uno_Mapping * pMapping_, uno_freeMappingFunc freeMapping_,
+ OUString aMappingName_ )
+ : nRef( 1 )
+ , pMapping( pMapping_ )
+ , freeMapping( freeMapping_ )
+ , aMappingName(std::move( aMappingName_ ))
+ {}
+};
+
+struct FctPtrHash
+{
+ size_t operator()( uno_Mapping * pKey ) const
+ { return reinterpret_cast<size_t>(pKey); }
+};
+
+}
+
+typedef std::unordered_map<
+ OUString, MappingEntry * > t_OUString2Entry;
+typedef std::unordered_map<
+ uno_Mapping *, MappingEntry *, FctPtrHash > t_Mapping2Entry;
+
+namespace {
+
+struct MappingsData
+{
+ Mutex aMappingsMutex;
+ t_OUString2Entry aName2Entry;
+ t_Mapping2Entry aMapping2Entry;
+
+ std::mutex aCallbacksMutex;
+ std::set< uno_getMappingFunc >
+ aCallbacks;
+
+ std::mutex aNegativeLibsMutex;
+ std::set<OUString> aNegativeLibs;
+};
+
+}
+
+static MappingsData & getMappingsData()
+{
+ //TODO This memory is leaked; see #i63473# for when this should be
+ // changed again:
+ static MappingsData * s_p(new MappingsData);
+
+ return *s_p;
+}
+
+namespace {
+
+/**
+ * This class mediates two different mapping via uno, e.g. form any language to uno,
+ * then from uno to any other language.
+ */
+struct uno_Mediate_Mapping : public uno_Mapping
+{
+ sal_Int32 nRef;
+
+ Environment aFrom;
+ Environment aTo;
+
+ Mapping aFrom2Uno;
+ Mapping aUno2To;
+
+ OUString aAddPurpose;
+
+ uno_Mediate_Mapping(
+ Environment aFrom_, Environment aTo_,
+ Mapping aFrom2Uno_, Mapping aUno2To_,
+ OUString aAddPurpose );
+};
+
+}
+
+extern "C"
+{
+
+static void mediate_free( uno_Mapping * pMapping )
+{
+ delete static_cast< uno_Mediate_Mapping * >( pMapping );
+}
+
+static void mediate_acquire( uno_Mapping * pMapping )
+{
+ if (1 == osl_atomic_increment(
+ & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
+ {
+ uno_registerMapping(
+ &pMapping, mediate_free,
+ static_cast< uno_Mediate_Mapping * >( pMapping )->aFrom.get(),
+ static_cast< uno_Mediate_Mapping * >( pMapping )->aTo.get(),
+ static_cast< uno_Mediate_Mapping * >( pMapping )->aAddPurpose.pData );
+ }
+}
+
+static void mediate_release( uno_Mapping * pMapping )
+{
+ if (! osl_atomic_decrement(
+ & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
+ {
+ uno_revokeMapping( pMapping );
+ }
+}
+
+static void mediate_mapInterface(
+ uno_Mapping * pMapping,
+ void ** ppOut, void * pInterface,
+ typelib_InterfaceTypeDescription * pInterfaceTypeDescr )
+{
+ OSL_ENSURE( pMapping && ppOut, "### null ptr!" );
+ if (!(pMapping && ppOut))
+ return;
+
+ uno_Mediate_Mapping * that = static_cast< uno_Mediate_Mapping * >( pMapping );
+ uno_Mapping * pFrom2Uno = that->aFrom2Uno.get();
+
+ uno_Interface * pUnoI = nullptr;
+ (*pFrom2Uno->mapInterface)( pFrom2Uno, reinterpret_cast<void **>(&pUnoI), pInterface, pInterfaceTypeDescr );
+ if (nullptr == pUnoI)
+ {
+ void * pOut = *ppOut;
+ if (nullptr != pOut)
+ {
+ uno_ExtEnvironment * pTo = that->aTo.get()->pExtEnv;
+ OSL_ENSURE( nullptr != pTo, "### cannot release out interface: leaking!" );
+ if (nullptr != pTo)
+ (*pTo->releaseInterface)( pTo, pOut );
+ *ppOut = nullptr; // set to 0 anyway, because mapping was not successful!
+ }
+ }
+ else
+ {
+ uno_Mapping * pUno2To = that->aUno2To.get();
+ (*pUno2To->mapInterface)( pUno2To, ppOut, pUnoI, pInterfaceTypeDescr );
+ (*pUnoI->release)( pUnoI );
+ }
+}
+}
+
+uno_Mediate_Mapping::uno_Mediate_Mapping(
+ Environment aFrom_, Environment aTo_,
+ Mapping aFrom2Uno_, Mapping aUno2To_,
+ OUString aAddPurpose_ )
+ : nRef( 1 )
+ , aFrom(std::move( aFrom_ ))
+ , aTo(std::move( aTo_ ))
+ , aFrom2Uno(std::move( aFrom2Uno_ ))
+ , aUno2To(std::move( aUno2To_ ))
+ , aAddPurpose(std::move( aAddPurpose_ ))
+{
+ uno_Mapping::acquire = mediate_acquire;
+ uno_Mapping::release = mediate_release;
+ uno_Mapping::mapInterface = mediate_mapInterface;
+}
+
+
+static OUString getMappingName(
+ const Environment & rFrom, const Environment & rTo, std::u16string_view rAddPurpose )
+{
+ OUStringBuffer aKey( 64 );
+ aKey.append( rAddPurpose );
+ aKey.append( ';' );
+ aKey.append( rFrom.getTypeName() );
+ aKey.append( '[' );
+ aKey.append( reinterpret_cast< sal_IntPtr >(rFrom.get()), 16 );
+ aKey.append( "];" );
+ aKey.append( rTo.getTypeName() );
+ aKey.append( '[' );
+ aKey.append( reinterpret_cast< sal_IntPtr >(rTo.get()), 16 );
+ aKey.append( ']' );
+ return aKey.makeStringAndClear();
+}
+
+static OUString getBridgeName(
+ const Environment & rFrom, const Environment & rTo, std::u16string_view rAddPurpose )
+{
+ OUStringBuffer aBridgeName( 16 );
+ if (!rAddPurpose.empty())
+ {
+ aBridgeName.append( rAddPurpose );
+ aBridgeName.append( '_' );
+ }
+ aBridgeName.append( EnvDcp::getTypeName(rFrom.getTypeName()) );
+ aBridgeName.append( '_' );
+ aBridgeName.append( EnvDcp::getTypeName(rTo.getTypeName()) );
+ return aBridgeName.makeStringAndClear();
+}
+
+#ifndef DISABLE_DYNLOADING
+
+static void setNegativeBridge( const OUString & rBridgeName )
+{
+ MappingsData & rData = getMappingsData();
+ std::scoped_lock aGuard( rData.aNegativeLibsMutex );
+ rData.aNegativeLibs.insert( rBridgeName );
+}
+
+#endif
+
+#ifdef DISABLE_DYNLOADING
+
+static uno_ext_getMappingFunc selectMapFunc( const OUString & rBridgeName )
+{
+ if (rBridgeName.equalsAscii( CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" ))
+ return CPPU_ENV_uno_ext_getMapping;
+#if HAVE_FEATURE_JAVA
+ if (rBridgeName.equalsAscii( "java" "_uno" ))
+ return java_uno_ext_getMapping;
+#endif
+
+#if 0
+ // I don't think the affine or log bridges will be needed on any
+ // DISABLE_DYNLOADING platform (iOS at least, possibly Android), but if
+ // somebody wants to experiment, need to find out then whether these are
+ // needed.
+ if (rBridgeName.equalsAscii( "affine_uno_uno" ))
+ return affine_uno_uno_ext_getMapping;
+ if (rBridgeName.equalsAscii( "log_uno_uno" ))
+ return log_uno_uno_ext_getMapping;
+#endif
+ return 0;
+}
+
+#else
+
+static bool loadModule(osl::Module & rModule, const OUString & rBridgeName)
+{
+ bool bNeg;
+ {
+ MappingsData & rData = getMappingsData();
+ std::scoped_lock aGuard( rData.aNegativeLibsMutex );
+ const auto iFind( rData.aNegativeLibs.find( rBridgeName ) );
+ bNeg = (iFind != rData.aNegativeLibs.end());
+ }
+
+ if (!bNeg)
+ {
+ bool bModule;
+ try {
+ bModule = cppu::detail::loadModule(rModule, rBridgeName);
+ }
+ catch(...) {
+ // convert throw to return false
+ bModule = false;
+ }
+
+ if (bModule)
+ return true;
+
+ setNegativeBridge( rBridgeName ); // no load again
+ }
+ return false;
+}
+
+#endif
+
+
+static Mapping loadExternalMapping(
+ const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
+{
+ OSL_ASSERT( rFrom.is() && rTo.is() );
+ if (rFrom.is() && rTo.is())
+ {
+#ifdef DISABLE_DYNLOADING
+ OUString aName;
+ uno_ext_getMappingFunc fpGetMapFunc = 0;
+
+ if (EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO)
+ {
+ aName = getBridgeName( rTo, rFrom, rAddPurpose );
+ fpGetMapFunc = selectMapFunc( aName );
+ }
+ if (! fpGetMapFunc)
+ {
+ aName = getBridgeName( rFrom, rTo, rAddPurpose );
+ fpGetMapFunc = selectMapFunc( aName );
+ }
+ if (! fpGetMapFunc)
+ {
+ aName = getBridgeName( rTo, rFrom, rAddPurpose );
+ fpGetMapFunc = selectMapFunc( aName );
+ }
+
+ if (! fpGetMapFunc)
+ {
+ SAL_INFO("cppu", "Could not find mapfunc for " << aName);
+ return Mapping();
+ }
+
+ if (fpGetMapFunc)
+ {
+ Mapping aExt;
+ (*fpGetMapFunc)( (uno_Mapping **)&aExt, rFrom.get(), rTo.get() );
+ OSL_ASSERT( aExt.is() );
+ if (aExt.is())
+ return aExt;
+ SAL_INFO("cppu", "Could not load external mapping for " << aName);
+ }
+#else
+ // find proper lib
+ osl::Module aModule;
+ bool bModule(false);
+ OUString aName;
+
+ if ( EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO )
+ {
+ aName = getBridgeName( rTo, rFrom, rAddPurpose );
+ bModule = loadModule( aModule, aName );
+ }
+ if (!bModule)
+ {
+ aName = getBridgeName( rFrom, rTo, rAddPurpose );
+ bModule = loadModule( aModule, aName );
+ }
+ if (!bModule)
+ {
+ aName = getBridgeName( rTo, rFrom, rAddPurpose );
+ bModule = loadModule( aModule, aName );
+ }
+
+ if (bModule)
+ {
+ uno_ext_getMappingFunc fpGetMapFunc =
+ reinterpret_cast<uno_ext_getMappingFunc>(aModule.getSymbol( UNO_EXT_GETMAPPING ));
+
+ if (fpGetMapFunc)
+ {
+ Mapping aExt;
+ (*fpGetMapFunc)( reinterpret_cast<uno_Mapping **>(&aExt), rFrom.get(), rTo.get() );
+ OSL_ASSERT( aExt.is() );
+ if (aExt.is())
+ {
+ aModule.release();
+ return aExt;
+ }
+ }
+ aModule.unload();
+ setNegativeBridge( aName );
+ }
+#endif
+ }
+ return Mapping();
+}
+
+
+static Mapping getDirectMapping(
+ const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose = OUString() )
+
+{
+ OSL_ASSERT( rFrom.is() && rTo.is() );
+ if (rFrom.is() && rTo.is())
+ {
+ MappingsData & rData = getMappingsData();
+ ClearableMutexGuard aGuard( rData.aMappingsMutex );
+
+ // try to find registered mapping
+ const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
+ getMappingName( rFrom, rTo, rAddPurpose ) ) );
+
+ if (iFind == rData.aName2Entry.end())
+ {
+ aGuard.clear();
+ return loadExternalMapping( rFrom, rTo, rAddPurpose );
+ }
+ return Mapping( (*iFind).second->pMapping );
+ }
+ return Mapping();
+}
+
+
+static Mapping createMediateMapping(
+ const Environment & rFrom, const Environment & rTo,
+ const Mapping & rFrom2Uno, const Mapping & rUno2To,
+ const OUString & rAddPurpose )
+{
+ uno_Mapping * pRet = new uno_Mediate_Mapping(
+ rFrom, rTo, rFrom2Uno, rUno2To, rAddPurpose ); // ref count initially 1
+ uno_registerMapping(
+ &pRet, mediate_free, rFrom.get(), rTo.get(), rAddPurpose.pData );
+ Mapping aRet( pRet );
+ (*pRet->release)( pRet );
+ return aRet;
+}
+
+static Mapping getMediateMapping(
+ const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
+{
+ Environment aUno;
+ Mapping aUno2To;
+
+ // backwards: from dest to source of mapping chain
+
+ // connect to uno
+ OUString aUnoEnvTypeName( UNO_LB_UNO );
+ if (rTo.getTypeName() == aUnoEnvTypeName) // to is uno
+ {
+ aUno = rTo;
+ // no Uno2To mapping necessary
+ }
+ else
+ {
+ // get registered uno env
+ ::uno_getEnvironment( reinterpret_cast<uno_Environment **>(&aUno), aUnoEnvTypeName.pData, nullptr );
+
+ aUno2To = getDirectMapping( aUno, rTo );
+ // : uno <-> to
+ if (! aUno2To.is())
+ return Mapping();
+ }
+
+ // connect to uno
+ if (!rAddPurpose.isEmpty()) // insert purpose mapping between new ano_uno <-> uno
+ {
+ // create anonymous uno env
+ Environment aAnUno;
+ ::uno_createEnvironment( reinterpret_cast<uno_Environment **>(&aAnUno), aUnoEnvTypeName.pData, nullptr );
+
+ Mapping aAnUno2Uno( getDirectMapping( aAnUno, aUno, rAddPurpose ) );
+ if (! aAnUno2Uno.is())
+ return Mapping();
+
+ if (aUno2To.is()) // to is not uno
+ {
+ // create another purposed mediate mapping
+ aUno2To = createMediateMapping( aAnUno, rTo, aAnUno2Uno, aUno2To, rAddPurpose );
+ // : ano_uno <-> uno <-> to
+ }
+ else
+ {
+ aUno2To = aAnUno2Uno;
+ // : ano_uno <-> to (i.e., uno)
+ }
+ aUno = aAnUno;
+ }
+
+ Mapping aFrom2Uno( getDirectMapping( rFrom, aUno ) );
+ if (aFrom2Uno.is() && aUno2To.is())
+ {
+ return createMediateMapping( rFrom, rTo, aFrom2Uno, aUno2To, rAddPurpose );
+ // : from <-> some uno ...
+ }
+
+ return Mapping();
+}
+}
+
+using namespace ::cppu;
+
+extern "C"
+{
+
+void SAL_CALL uno_getMapping(
+ uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo,
+ rtl_uString * pAddPurpose )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping != nullptr);
+ assert(pFrom != nullptr);
+ assert(pTo != nullptr);
+ if (*ppMapping)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ *ppMapping = nullptr;
+ }
+
+ Mapping aRet;
+ Environment aFrom( pFrom ), aTo( pTo );
+
+ OUString aAddPurpose;
+ if (pAddPurpose)
+ aAddPurpose = pAddPurpose;
+
+ MappingsData & rData = getMappingsData();
+
+ // try registered mapping
+ {
+ MutexGuard aGuard( rData.aMappingsMutex );
+ const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
+ getMappingName( aFrom, aTo, aAddPurpose ) ) );
+ if (iFind != rData.aName2Entry.end())
+ aRet = (*iFind).second->pMapping;
+ }
+
+ // See if an identity mapping does fit.
+ if (!aRet.is() && pFrom == pTo && aAddPurpose.isEmpty())
+ aRet = createIdentityMapping(pFrom);
+
+ if (!aRet.is())
+ {
+ getCascadeMapping(ppMapping, pFrom, pTo, pAddPurpose);
+
+ if (*ppMapping)
+ return;
+
+ // try callback chain
+ {
+ std::unique_lock aGuard(rData.aCallbacksMutex);
+ for (const auto& rCallback : rData.aCallbacks)
+ {
+ (*rCallback)(ppMapping, pFrom, pTo, aAddPurpose.pData);
+ if (*ppMapping)
+ return;
+ }
+ }
+
+ aRet = loadExternalMapping( aFrom, aTo, aAddPurpose ); // direct try
+ if (! aRet.is())
+ aRet = getMediateMapping( aFrom, aTo, aAddPurpose ); // try via uno
+ }
+
+ if (aRet.is())
+ {
+ (*aRet.get()->acquire)( aRet.get() );
+ *ppMapping = aRet.get();
+ }
+}
+
+void SAL_CALL uno_getMappingByName(
+ uno_Mapping ** ppMapping, rtl_uString * pFrom, rtl_uString * pTo,
+ rtl_uString * pAddPurpose )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppMapping && pFrom && pTo && "### null ptr!");
+ if (*ppMapping)
+ {
+ (*(*ppMapping)->release)( *ppMapping );
+ *ppMapping = nullptr;
+ }
+
+ uno_Environment * pEFrom = nullptr;
+ uno_getEnvironment( &pEFrom, pFrom, nullptr );
+ OSL_ENSURE( pEFrom, "### cannot get source environment!" );
+ if (pEFrom)
+ {
+ uno_Environment * pETo = nullptr;
+ uno_getEnvironment( &pETo, pTo, nullptr );
+ OSL_ENSURE( pETo, "### cannot get target environment!" );
+ if (pETo)
+ {
+ ::uno_getMapping( ppMapping, pEFrom, pETo, pAddPurpose );
+ (*pETo->release)( pETo );
+ }
+ (*pEFrom->release)( pEFrom );
+ }
+}
+
+
+void SAL_CALL uno_registerMapping(
+ uno_Mapping ** ppMapping, uno_freeMappingFunc freeMapping,
+ uno_Environment * pFrom, uno_Environment * pTo, rtl_uString * pAddPurpose )
+ SAL_THROW_EXTERN_C()
+{
+ MappingsData & rData = getMappingsData();
+ ClearableMutexGuard aGuard( rData.aMappingsMutex );
+
+ const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( *ppMapping ) );
+ if (iFind == rData.aMapping2Entry.end())
+ {
+ OUString aMappingName(
+ getMappingName( pFrom, pTo, pAddPurpose ? OUString(pAddPurpose) : OUString() ) );
+ SAL_INFO("cppu", "> inserting new mapping: " << aMappingName);
+ // count initially 1
+ MappingEntry * pEntry = new MappingEntry( *ppMapping, freeMapping, aMappingName );
+ rData.aName2Entry[ aMappingName ] = pEntry;
+ rData.aMapping2Entry[ *ppMapping ] = pEntry;
+ }
+ else
+ {
+ MappingEntry * pEntry = (*iFind).second;
+ ++pEntry->nRef;
+
+ if (pEntry->pMapping != *ppMapping) // exchange mapping to be registered
+ {
+ (*pEntry->pMapping->acquire)( pEntry->pMapping );
+ --pEntry->nRef; // correct count; kill mapping to be registered
+ aGuard.clear();
+ (*freeMapping)( *ppMapping );
+ *ppMapping = pEntry->pMapping;
+ }
+ }
+}
+
+void SAL_CALL uno_revokeMapping(
+ uno_Mapping * pMapping )
+ SAL_THROW_EXTERN_C()
+{
+ MappingsData & rData = getMappingsData();
+ ClearableMutexGuard aGuard( rData.aMappingsMutex );
+
+ const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( pMapping ) );
+ OSL_ASSERT( iFind != rData.aMapping2Entry.end() );
+ MappingEntry * pEntry = (*iFind).second;
+ if (! --pEntry->nRef)
+ {
+ rData.aMapping2Entry.erase( pEntry->pMapping );
+ rData.aName2Entry.erase( pEntry->aMappingName );
+ aGuard.clear();
+ SAL_INFO("cppu", "> revoking mapping " << pEntry->aMappingName);
+ (*pEntry->freeMapping)( pEntry->pMapping );
+ delete pEntry;
+ }
+}
+
+
+void SAL_CALL uno_registerMappingCallback(
+ uno_getMappingFunc pCallback )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( pCallback, "### null ptr!" );
+ MappingsData & rData = getMappingsData();
+ std::unique_lock aGuard( rData.aCallbacksMutex );
+ rData.aCallbacks.insert( pCallback );
+}
+
+void SAL_CALL uno_revokeMappingCallback(
+ uno_getMappingFunc pCallback )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( pCallback, "### null ptr!" );
+ MappingsData & rData = getMappingsData();
+ std::unique_lock aGuard( rData.aCallbacksMutex );
+ rData.aCallbacks.erase( pCallback );
+}
+} // extern "C"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/loadmodule.cxx b/cppu/source/uno/loadmodule.cxx
new file mode 100644
index 000000000..f2811a595
--- /dev/null
+++ b/cppu/source/uno/loadmodule.cxx
@@ -0,0 +1,75 @@
+/* -*- 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 <osl/module.h>
+#include <osl/module.hxx>
+#include <rtl/malformeduriexception.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#include "loadmodule.hxx"
+
+namespace cppu::detail {
+
+#ifndef DISABLE_DYNLOADING
+
+bool loadModule(osl::Module& rModule, OUString const & name) {
+ static OUString base = [] {
+ OUString url;
+ if (!osl::Module::getUrlFromAddress(
+ reinterpret_cast<oslGenericFunction>(&loadModule), url))
+ {
+ SAL_WARN("cppu", "osl::Module::getUrlFromAddress failed");
+ return OUString();
+ }
+ assert(!url.isEmpty());
+ return url;
+ }();
+ if (base.isEmpty()) {
+ SAL_INFO("cppu", "osl::Module::getUrlFromAddress had failed");
+ return false;
+ }
+ OUString b =
+#if defined SAL_DLLPREFIX
+ SAL_DLLPREFIX +
+#endif
+ name +
+ SAL_DLLEXTENSION;
+ try {
+ b = rtl::Uri::convertRelToAbs(base, b);
+ } catch (rtl::MalformedUriException & e) {
+ SAL_INFO("cppu", "rtl::MalformedUriException <" << e.getMessage() << ">");
+ return false;
+ }
+ return rModule.load(
+ b,
+ SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_LAZY);
+}
+
+#endif
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/loadmodule.hxx b/cppu/source/uno/loadmodule.hxx
new file mode 100644
index 000000000..694b14024
--- /dev/null
+++ b/cppu/source/uno/loadmodule.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+#include <rtl/ustring.hxx>
+
+namespace osl
+{
+class Module;
+}
+
+namespace cppu::detail
+{
+#ifndef DISABLE_DYNLOADING
+
+/** Load a module.
+
+ @param name
+ the nucleus of a module name (without any "lib...so", ".dll", etc.
+ decoration, and without a path).
+
+ @return false if the module could not be loaded, otherwise true
+*/
+bool loadModule(osl::Module& rModule, OUString const& name);
+
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/prim.hxx b/cppu/source/uno/prim.hxx
new file mode 100644
index 000000000..733baec0f
--- /dev/null
+++ b/cppu/source/uno/prim.hxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <typelib/typedescription.h>
+#include <typelib/typeclass.h>
+#include <uno/sequence2.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+#include <uno/mapping.h>
+#include <uno/dispatcher.h>
+
+#include <osl/interlck.h>
+#include <stdint.h>
+
+namespace cppu
+{
+
+extern uno_Sequence g_emptySeq;
+extern typelib_TypeDescriptionReference * g_pVoidType;
+
+
+inline void * _map(
+ void * p,
+ typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr,
+ uno_Mapping * mapping )
+
+{
+ void * pRet = nullptr;
+ if (p)
+ {
+ if (pTypeDescr)
+ {
+ (*mapping->mapInterface)(
+ mapping, &pRet, p, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTypeDescr) );
+ }
+ else
+ {
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ (*mapping->mapInterface)(
+ mapping, &pRet, p, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTypeDescr) );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ }
+ return pRet;
+}
+
+inline void _acquire( void * p, uno_AcquireFunc acquire )
+{
+ if (p)
+ {
+ if (acquire)
+ {
+ (*acquire)( p );
+ }
+ else
+ {
+ (*static_cast<uno_Interface *>(p)->acquire)( static_cast<uno_Interface *>(p) );
+ }
+ }
+}
+
+inline void _release( void * p, uno_ReleaseFunc release )
+{
+ if (p)
+ {
+ if (release)
+ {
+ (*release)( p );
+ }
+ else
+ {
+ (*static_cast<uno_Interface *>(p)->release)( static_cast<uno_Interface *>(p) );
+ }
+ }
+}
+
+
+inline sal_uInt32 calcSeqMemSize(
+ sal_Int32 nElementSize, sal_Int32 nElements )
+{
+ sal_uInt64 nSize =
+ static_cast<sal_uInt64>(SAL_SEQUENCE_HEADER_SIZE) +
+ (static_cast<sal_uInt64>(nElementSize) * static_cast<sal_uInt64>(nElements));
+ if (nSize > 0xffffffffU)
+ return 0;
+ else
+ return static_cast<sal_uInt32>(nSize);
+}
+
+
+inline uno_Sequence * createEmptySequence()
+{
+ osl_atomic_increment( &g_emptySeq.nRefCount );
+ return &g_emptySeq;
+}
+
+inline typelib_TypeDescriptionReference * _getVoidType()
+{
+ if (! g_pVoidType)
+ {
+ g_pVoidType = * ::typelib_static_type_getByTypeClass( typelib_TypeClass_VOID );
+ }
+ ::typelib_typedescriptionreference_acquire( g_pVoidType );
+ return g_pVoidType;
+}
+
+inline void CONSTRUCT_EMPTY_ANY(uno_Any * pAny) {
+ pAny->pType = _getVoidType();
+#if OSL_DEBUG_LEVEL > 0
+ pAny->pData = reinterpret_cast<void *>(uintptr_t(0xdeadbeef));
+#else
+ pAny->pData = pAny;
+#endif
+}
+
+#define TYPE_ACQUIRE( pType ) \
+ osl_atomic_increment( &(pType)->nRefCount );
+
+
+extern "C" void * binuno_queryInterface(
+ void * pUnoI, typelib_TypeDescriptionReference * pDestType );
+
+
+inline bool _type_equals(
+ typelib_TypeDescriptionReference const * pType1, typelib_TypeDescriptionReference const * pType2 )
+
+{
+ return (pType1 == pType2 ||
+ (pType1->eTypeClass == pType2->eTypeClass &&
+ pType1->pTypeName->length == pType2->pTypeName->length &&
+ ::rtl_ustr_compare( pType1->pTypeName->buffer, pType2->pTypeName->buffer ) == 0));
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cppu/source/uno/sequence.cxx b/cppu/source/uno/sequence.cxx
new file mode 100644
index 000000000..c467f2c38
--- /dev/null
+++ b/cppu/source/uno/sequence.cxx
@@ -0,0 +1,912 @@
+/* -*- 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 <string.h>
+
+#include <osl/diagnose.h>
+#include <osl/interlck.h>
+#include <typelib/typedescription.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+
+#include "constr.hxx"
+#include "copy.hxx"
+#include "destr.hxx"
+
+
+using namespace cppu;
+
+namespace cppu
+{
+
+
+static uno_Sequence * reallocSeq(
+ uno_Sequence * pReallocate, std::size_t nElementSize, sal_Int32 nElements )
+{
+ OSL_ASSERT( nElements >= 0 );
+ uno_Sequence * pNew = nullptr;
+ sal_uInt32 nSize = calcSeqMemSize( nElementSize, nElements );
+ if (nSize > 0)
+ {
+ if (pReallocate == nullptr)
+ {
+ pNew = static_cast<uno_Sequence *>(std::malloc( nSize ));
+ }
+ else
+ {
+ pNew = static_cast<uno_Sequence *>(std::realloc( pReallocate, nSize ));
+ }
+ if (pNew != nullptr)
+ {
+ // header init
+ pNew->nRefCount = 1;
+ pNew->nElements = nElements;
+ }
+ }
+ return pNew;
+}
+
+
+static bool idefaultConstructElements(
+ uno_Sequence ** ppSeq,
+ typelib_TypeDescriptionReference * pElementType,
+ sal_Int32 nStartIndex, sal_Int32 nStopIndex,
+ sal_Int32 nAlloc ) // >= 0 means (re)alloc memory for nAlloc elements
+{
+ uno_Sequence * pSeq = *ppSeq;
+ switch (pElementType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Unicode), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Unicode) * nStartIndex),
+ 0,
+ sizeof(sal_Unicode) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Bool), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Bool) * nStartIndex),
+ 0,
+ sizeof(sal_Bool) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int8), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Int8) * nStartIndex),
+ 0,
+ sizeof(sal_Int8) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int16), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Int16) * nStartIndex),
+ 0,
+ sizeof(sal_Int16) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Int32) * nStartIndex),
+ 0,
+ sizeof(sal_Int32) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int64), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(sal_Int64) * nStartIndex),
+ 0,
+ sizeof(sal_Int64) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ {
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(float), nAlloc );
+ if (pSeq != nullptr)
+ {
+ float * pElements = reinterpret_cast<float *>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = 0.0;
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_DOUBLE:
+ {
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(double), nAlloc );
+ if (pSeq != nullptr)
+ {
+ double * pElements = reinterpret_cast<double *>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = 0.0;
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRING:
+ {
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(rtl_uString *), nAlloc );
+ if (pSeq != nullptr)
+ {
+ rtl_uString ** pElements = reinterpret_cast<rtl_uString **>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = nullptr;
+ rtl_uString_new( &pElements[nPos] );
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ if (nAlloc >= 0)
+ {
+ pSeq = reallocSeq(
+ pSeq, sizeof(typelib_TypeDescriptionReference *), nAlloc );
+ }
+ if (pSeq != nullptr)
+ {
+ typelib_TypeDescriptionReference ** pElements =
+ reinterpret_cast<typelib_TypeDescriptionReference **>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = _getVoidType();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(uno_Any), nAlloc );
+ if (pSeq != nullptr)
+ {
+ uno_Any * pElements = reinterpret_cast<uno_Any *>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ CONSTRUCT_EMPTY_ANY( &pElements[nPos] );
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_ENUM:
+ {
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc );
+ if (pSeq != nullptr)
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 eEnum =
+ reinterpret_cast<typelib_EnumTypeDescription *>(
+ pElementTypeDescr)->nDefaultEnumValue;
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+
+ sal_Int32 * pElements = reinterpret_cast<sal_Int32 *>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = eEnum;
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 nElementSize = pElementTypeDescr->nSize;
+
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, nElementSize, nAlloc );
+ if (pSeq != nullptr)
+ {
+ char * pElements = pSeq->elements;
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ _defaultConstructStruct(
+ pElements + (nElementSize * nPos),
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr) );
+ }
+ }
+
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE:
+ {
+ if (nAlloc >= 0)
+ {
+ // coverity[suspicious_sizeof : FALSE] - sizeof(uno_Sequence*) is correct here
+ pSeq = reallocSeq(pSeq, sizeof(uno_Sequence*), nAlloc);
+ }
+ if (pSeq != nullptr)
+ {
+ uno_Sequence ** pElements =
+ reinterpret_cast<uno_Sequence **>(pSeq->elements);
+ for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos )
+ {
+ pElements[nPos] = createEmptySequence();
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE: // either C++ or C-UNO interface
+ if (nAlloc >= 0)
+ pSeq = reallocSeq( pSeq, sizeof(void *), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memset(
+ pSeq->elements + (sizeof(void *) * nStartIndex),
+ 0,
+ sizeof(void *) * (nStopIndex - nStartIndex) );
+ }
+ break;
+ default:
+ OSL_FAIL( "### unexpected element type!" );
+ pSeq = nullptr;
+ break;
+ }
+
+ if (pSeq == nullptr)
+ {
+ OSL_ASSERT( nAlloc >= 0 ); // must have been an allocation failure
+ return false;
+ }
+ *ppSeq = pSeq;
+ return true;
+}
+
+// coverity[ -tainted_data_sink : arg-1 ]
+static bool icopyConstructFromElements(
+ uno_Sequence ** ppSeq, void * pSourceElements,
+ typelib_TypeDescriptionReference * pElementType,
+ sal_Int32 nStopIndex,
+ uno_AcquireFunc acquire,
+ sal_Int32 nAlloc )
+{
+ uno_Sequence * pSeq = *ppSeq;
+ switch (pElementType->eTypeClass)
+ {
+ case typelib_TypeClass_CHAR:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Unicode), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Unicode) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Bool), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Bool) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_BYTE:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int8), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Int8) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int16), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Int16) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Int32) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int64), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Int64) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ pSeq = reallocSeq( pSeq, sizeof(float), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(float) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ pSeq = reallocSeq( pSeq, sizeof(double), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(double) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_ENUM:
+ pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc );
+ if (pSeq != nullptr)
+ {
+ memcpy(
+ pSeq->elements,
+ pSourceElements,
+ sizeof(sal_Int32) * nStopIndex );
+ }
+ break;
+ case typelib_TypeClass_STRING:
+ {
+ pSeq = reallocSeq( pSeq, sizeof(rtl_uString *), nAlloc );
+ if (pSeq != nullptr)
+ {
+ rtl_uString ** pDestElements = reinterpret_cast<rtl_uString **>(pSeq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ // This code tends to trigger coverity's overrun-buffer-arg warning
+ // coverity[index_parm_via_loop_bound] - https://communities.coverity.com/thread/2993
+ ::rtl_uString_acquire(
+ static_cast<rtl_uString **>(pSourceElements)[nPos] );
+ pDestElements[nPos] = static_cast<rtl_uString **>(pSourceElements)[nPos];
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_TYPE:
+ {
+ pSeq = reallocSeq(
+ pSeq, sizeof(typelib_TypeDescriptionReference *), nAlloc );
+ if (pSeq != nullptr)
+ {
+ typelib_TypeDescriptionReference ** pDestElements =
+ reinterpret_cast<typelib_TypeDescriptionReference **>(pSeq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ TYPE_ACQUIRE(
+ static_cast<typelib_TypeDescriptionReference **>(
+ pSourceElements)[nPos] );
+ pDestElements[nPos] =
+ static_cast<typelib_TypeDescriptionReference **>(
+ pSourceElements)[nPos];
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_ANY:
+ {
+ pSeq = reallocSeq( pSeq, sizeof(uno_Any), nAlloc );
+ if (pSeq != nullptr)
+ {
+ uno_Any * pDestElements = reinterpret_cast<uno_Any *>(pSeq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ uno_Any * pSource = static_cast<uno_Any *>(pSourceElements) + nPos;
+ _copyConstructAny(
+ &pDestElements[nPos],
+ pSource->pData,
+ pSource->pType, nullptr,
+ acquire, nullptr );
+ }
+ }
+ break;
+ }
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ sal_Int32 nElementSize = pElementTypeDescr->nSize;
+
+ pSeq = reallocSeq( pSeq, nElementSize, nAlloc );
+ if (pSeq != nullptr)
+ {
+ char * pDestElements = pSeq->elements;
+
+ typelib_CompoundTypeDescription * pTypeDescr =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ char * pDest =
+ pDestElements + (nElementSize * nPos);
+ char * pSource =
+ static_cast<char *>(pSourceElements) + (nElementSize * nPos);
+
+ if (pTypeDescr->pBaseTypeDescription)
+ {
+ // copy base value
+ _copyConstructStruct(
+ pDest, pSource,
+ pTypeDescr->pBaseTypeDescription, acquire, nullptr );
+ }
+
+ // then copy members
+ typelib_TypeDescriptionReference ** ppTypeRefs =
+ pTypeDescr->ppTypeRefs;
+ sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets;
+ sal_Int32 nDescr = pTypeDescr->nMembers;
+
+ while (nDescr--)
+ {
+ ::uno_type_copyData(
+ pDest + pMemberOffsets[nDescr],
+ pSource + pMemberOffsets[nDescr],
+ ppTypeRefs[nDescr], acquire );
+ }
+ }
+ }
+
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ break;
+ }
+ case typelib_TypeClass_SEQUENCE: // sequence of sequence
+ {
+ // coverity[suspicious_sizeof : FALSE] - sizeof(uno_Sequence*) is correct here
+ pSeq = reallocSeq(pSeq, sizeof(uno_Sequence*), nAlloc);
+ if (pSeq != nullptr)
+ {
+ typelib_TypeDescription * pElementTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType );
+ typelib_TypeDescriptionReference * pSeqElementType =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pElementTypeDescr)->pType;
+ uno_Sequence ** pDestElements = reinterpret_cast<uno_Sequence **>(pSeq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ uno_Sequence * pNew = icopyConstructSequence(
+ static_cast<uno_Sequence **>(pSourceElements)[nPos],
+ pSeqElementType, acquire, nullptr );
+ OSL_ASSERT( pNew != nullptr );
+ // ought never be a memory allocation problem,
+ // because of reference counted sequence handles
+ pDestElements[ nPos ] = pNew;
+ }
+ TYPELIB_DANGER_RELEASE( pElementTypeDescr );
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE:
+ {
+ pSeq = reallocSeq( pSeq, sizeof(void *), nAlloc );
+ if (pSeq != nullptr)
+ {
+ void ** pDestElements = reinterpret_cast<void **>(pSeq->elements);
+ for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos )
+ {
+ pDestElements[nPos] = static_cast<void **>(pSourceElements)[nPos];
+ _acquire( pDestElements[nPos], acquire );
+ }
+ }
+ break;
+ }
+ default:
+ OSL_FAIL( "### unexpected element type!" );
+ pSeq = nullptr;
+ break;
+ }
+
+ if (pSeq == nullptr)
+ {
+ return false; // allocation failure
+ }
+ *ppSeq = pSeq;
+ return true;
+}
+
+
+static bool ireallocSequence(
+ uno_Sequence ** ppSequence,
+ typelib_TypeDescriptionReference * pElementType,
+ sal_Int32 nSize,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+{
+ bool ret = true;
+ uno_Sequence * pSeq = *ppSequence;
+ sal_Int32 nElements = pSeq->nElements;
+
+ if (pSeq->nRefCount > 1 ||
+ // not mem-copyable elements?
+ typelib_TypeClass_ANY == pElementType->eTypeClass ||
+ typelib_TypeClass_STRUCT == pElementType->eTypeClass ||
+ typelib_TypeClass_EXCEPTION == pElementType->eTypeClass)
+ {
+ // split sequence and construct new one from scratch
+ uno_Sequence * pNew = nullptr;
+
+ sal_Int32 nRest = nSize - nElements;
+ sal_Int32 nCopy = (nRest > 0 ? nElements : nSize);
+
+ if (nCopy >= 0)
+ {
+ ret = icopyConstructFromElements(
+ &pNew, pSeq->elements, pElementType,
+ nCopy, acquire,
+ nSize ); // alloc to nSize
+ }
+ if (ret && nRest > 0)
+ {
+ ret = idefaultConstructElements(
+ &pNew, pElementType,
+ nCopy, nSize,
+ nCopy >= 0 ? -1 /* no mem allocation */ : nSize );
+ }
+
+ if (ret)
+ {
+ // destruct sequence
+ if (osl_atomic_decrement( &pSeq->nRefCount ) == 0)
+ {
+ if (nElements > 0)
+ {
+ idestructElements(
+ pSeq->elements, pElementType,
+ 0, nElements, release );
+ }
+ std::free( pSeq );
+ }
+ *ppSequence = pNew;
+ }
+ }
+ else
+ {
+ OSL_ASSERT( pSeq->nRefCount == 1 );
+ if (nSize > nElements) // default construct the rest
+ {
+ ret = idefaultConstructElements(
+ ppSequence, pElementType,
+ nElements, nSize,
+ nSize ); // realloc to nSize
+ }
+ else // or destruct the rest and realloc mem
+ {
+ sal_Int32 nElementSize = idestructElements(
+ pSeq->elements, pElementType,
+ nSize, nElements, release );
+ // warning: it is assumed that the following will never fail,
+ // else this leads to a sequence null handle
+ *ppSequence = reallocSeq( pSeq, nElementSize, nSize );
+ OSL_ASSERT( *ppSequence != nullptr );
+ ret = (*ppSequence != nullptr);
+ }
+ }
+
+ return ret;
+}
+
+}
+
+extern "C"
+{
+
+sal_Bool SAL_CALL uno_type_sequence_construct(
+ uno_Sequence ** ppSequence, typelib_TypeDescriptionReference * pType,
+ void * pElements, sal_Int32 len,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ assert( len >= 0 );
+ bool ret;
+ if (len)
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+
+ typelib_TypeDescriptionReference * pElementType =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType;
+
+ *ppSequence = nullptr;
+ if (pElements == nullptr)
+ {
+ ret = idefaultConstructElements(
+ ppSequence, pElementType,
+ 0, len,
+ len ); // alloc to len
+ }
+ else
+ {
+ ret = icopyConstructFromElements(
+ ppSequence, pElements, pElementType,
+ len, acquire,
+ len ); // alloc to len
+ }
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ else
+ {
+ *ppSequence = createEmptySequence();
+ ret = true;
+ }
+
+ OSL_ASSERT( (*ppSequence != nullptr) == ret );
+ return ret;
+}
+
+
+sal_Bool SAL_CALL uno_sequence_construct(
+ uno_Sequence ** ppSequence, typelib_TypeDescription * pTypeDescr,
+ void * pElements, sal_Int32 len,
+ uno_AcquireFunc acquire )
+ SAL_THROW_EXTERN_C()
+{
+ bool ret;
+ if (len > 0)
+ {
+ typelib_TypeDescriptionReference * pElementType =
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType;
+
+ *ppSequence = nullptr;
+ if (pElements == nullptr)
+ {
+ ret = idefaultConstructElements(
+ ppSequence, pElementType,
+ 0, len,
+ len ); // alloc to len
+ }
+ else
+ {
+ ret = icopyConstructFromElements(
+ ppSequence, pElements, pElementType,
+ len, acquire,
+ len ); // alloc to len
+ }
+ }
+ else
+ {
+ *ppSequence = createEmptySequence();
+ ret = true;
+ }
+
+ OSL_ASSERT( (*ppSequence != nullptr) == ret );
+ return ret;
+}
+
+
+sal_Bool SAL_CALL uno_type_sequence_realloc(
+ uno_Sequence ** ppSequence, typelib_TypeDescriptionReference * pType,
+ sal_Int32 nSize, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ assert(ppSequence && "### null ptr!");
+ assert(nSize >= 0 && "### new size must be at least 0!");
+
+ bool ret = true;
+ if (nSize != (*ppSequence)->nElements)
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+ ret = ireallocSequence(
+ ppSequence, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ nSize, acquire, release );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ return ret;
+}
+
+
+sal_Bool SAL_CALL uno_sequence_realloc(
+ uno_Sequence ** ppSequence, typelib_TypeDescription * pTypeDescr,
+ sal_Int32 nSize, uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( ppSequence, "### null ptr!" );
+ OSL_ENSURE( nSize >= 0, "### new size must be at least 0!" );
+
+ bool ret = true;
+ if (nSize != (*ppSequence)->nElements)
+ {
+ ret = ireallocSequence(
+ ppSequence, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ nSize, acquire, release );
+ }
+ return ret;
+}
+
+
+sal_Bool SAL_CALL uno_type_sequence_reference2One(
+ uno_Sequence ** ppSequence,
+ typelib_TypeDescriptionReference * pType,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( ppSequence, "### null ptr!" );
+ bool ret = true;
+ uno_Sequence * pSequence = *ppSequence;
+ if (pSequence->nRefCount > 1)
+ {
+ uno_Sequence * pNew = nullptr;
+ if (pSequence->nElements > 0)
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, pType );
+
+ ret = icopyConstructFromElements(
+ &pNew, pSequence->elements,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ pSequence->nElements, acquire,
+ pSequence->nElements ); // alloc nElements
+ if (ret)
+ {
+ idestructSequence( *ppSequence, pType, pTypeDescr, release );
+ *ppSequence = pNew;
+ }
+
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ else
+ {
+ pNew = allocSeq( 0, 0 );
+ ret = (pNew != nullptr);
+ if (ret)
+ {
+ // easy destruction of empty sequence:
+ if (osl_atomic_decrement( &pSequence->nRefCount ) == 0)
+ std::free( pSequence );
+ *ppSequence = pNew;
+ }
+ }
+ }
+ return ret;
+}
+
+
+sal_Bool SAL_CALL uno_sequence_reference2One(
+ uno_Sequence ** ppSequence,
+ typelib_TypeDescription * pTypeDescr,
+ uno_AcquireFunc acquire, uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ OSL_ENSURE( ppSequence, "### null ptr!" );
+ bool ret = true;
+ uno_Sequence * pSequence = *ppSequence;
+ if (pSequence->nRefCount > 1)
+ {
+ uno_Sequence * pNew = nullptr;
+ if (pSequence->nElements > 0)
+ {
+ ret = icopyConstructFromElements(
+ &pNew, pSequence->elements,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType,
+ pSequence->nElements, acquire,
+ pSequence->nElements ); // alloc nElements
+ if (ret)
+ {
+ idestructSequence(
+ pSequence, pTypeDescr->pWeakRef, pTypeDescr, release );
+ *ppSequence = pNew;
+ }
+ }
+ else
+ {
+ pNew = allocSeq( 0, 0 );
+ ret = (pNew != nullptr);
+ if (ret)
+ {
+ // easy destruction of empty sequence:
+ if (osl_atomic_decrement( &pSequence->nRefCount ) == 0)
+ std::free( pSequence );
+ *ppSequence = pNew;
+ }
+ }
+
+ }
+ return ret;
+}
+
+
+void SAL_CALL uno_sequence_assign(
+ uno_Sequence ** ppDest,
+ uno_Sequence * pSource,
+ typelib_TypeDescription * pTypeDescr,
+ uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppDest != pSource)
+ {
+ osl_atomic_increment( &pSource->nRefCount );
+ idestructSequence( *ppDest, pTypeDescr->pWeakRef, pTypeDescr, release );
+ *ppDest = pSource;
+ }
+}
+
+
+void SAL_CALL uno_type_sequence_assign(
+ uno_Sequence ** ppDest,
+ uno_Sequence * pSource,
+ typelib_TypeDescriptionReference * pType,
+ uno_ReleaseFunc release )
+ SAL_THROW_EXTERN_C()
+{
+ if (*ppDest != pSource)
+ {
+ osl_atomic_increment( &pSource->nRefCount );
+ idestructSequence( *ppDest, pType, nullptr, release );
+ *ppDest = pSource;
+ }
+}
+
+void uno_type_sequence_destroy(
+ uno_Sequence * sequence, typelib_TypeDescriptionReference * type,
+ uno_ReleaseFunc release)
+ SAL_THROW_EXTERN_C()
+{
+ idestroySequence(sequence, type, nullptr, release);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */