From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- cppu/source/AffineBridge/AffineBridge.cxx | 360 +++ cppu/source/LogBridge/LogBridge.cxx | 262 +++ cppu/source/UnsafeBridge/UnsafeBridge.cxx | 144 ++ cppu/source/cppu/compat.cxx | 47 + cppu/source/cppu/cppu_opt.cxx | 66 + cppu/source/helper/purpenv/Proxy.hxx | 76 + .../helper/purpenv/helper_purpenv_Environment.cxx | 522 +++++ .../helper/purpenv/helper_purpenv_Mapping.cxx | 215 ++ .../source/helper/purpenv/helper_purpenv_Proxy.cxx | 504 ++++ cppu/source/threadpool/current.cxx | 210 ++ cppu/source/threadpool/current.hxx | 47 + cppu/source/threadpool/jobqueue.cxx | 177 ++ cppu/source/threadpool/jobqueue.hxx | 72 + cppu/source/threadpool/thread.cxx | 198 ++ cppu/source/threadpool/thread.hxx | 67 + cppu/source/threadpool/threadident.cxx | 120 + cppu/source/threadpool/threadpool.cxx | 476 ++++ cppu/source/threadpool/threadpool.hxx | 162 ++ cppu/source/typelib/static_types.cxx | 555 +++++ cppu/source/typelib/typelib.cxx | 2399 ++++++++++++++++++++ cppu/source/typelib/typelib.hxx | 45 + cppu/source/uno/EnvDcp.cxx | 43 + cppu/source/uno/EnvStack.cxx | 382 ++++ cppu/source/uno/IdentityMapping.cxx | 105 + cppu/source/uno/IdentityMapping.hxx | 31 + cppu/source/uno/any.cxx | 142 ++ cppu/source/uno/assign.hxx | 449 ++++ cppu/source/uno/cascade_mapping.cxx | 308 +++ cppu/source/uno/cascade_mapping.hxx | 32 + cppu/source/uno/check.cxx | 335 +++ cppu/source/uno/constr.hxx | 138 ++ cppu/source/uno/copy.hxx | 655 ++++++ cppu/source/uno/data.cxx | 316 +++ cppu/source/uno/destr.hxx | 352 +++ cppu/source/uno/eq.hxx | 635 ++++++ cppu/source/uno/lbenv.cxx | 1147 ++++++++++ cppu/source/uno/lbmap.cxx | 754 ++++++ cppu/source/uno/loadmodule.cxx | 75 + cppu/source/uno/loadmodule.hxx | 47 + cppu/source/uno/prim.hxx | 153 ++ cppu/source/uno/sequence.cxx | 912 ++++++++ 41 files changed, 13735 insertions(+) create mode 100644 cppu/source/AffineBridge/AffineBridge.cxx create mode 100644 cppu/source/LogBridge/LogBridge.cxx create mode 100644 cppu/source/UnsafeBridge/UnsafeBridge.cxx create mode 100644 cppu/source/cppu/compat.cxx create mode 100644 cppu/source/cppu/cppu_opt.cxx create mode 100644 cppu/source/helper/purpenv/Proxy.hxx create mode 100644 cppu/source/helper/purpenv/helper_purpenv_Environment.cxx create mode 100644 cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx create mode 100644 cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx create mode 100644 cppu/source/threadpool/current.cxx create mode 100644 cppu/source/threadpool/current.hxx create mode 100644 cppu/source/threadpool/jobqueue.cxx create mode 100644 cppu/source/threadpool/jobqueue.hxx create mode 100644 cppu/source/threadpool/thread.cxx create mode 100644 cppu/source/threadpool/thread.hxx create mode 100644 cppu/source/threadpool/threadident.cxx create mode 100644 cppu/source/threadpool/threadpool.cxx create mode 100644 cppu/source/threadpool/threadpool.hxx create mode 100644 cppu/source/typelib/static_types.cxx create mode 100644 cppu/source/typelib/typelib.cxx create mode 100644 cppu/source/typelib/typelib.hxx create mode 100644 cppu/source/uno/EnvDcp.cxx create mode 100644 cppu/source/uno/EnvStack.cxx create mode 100644 cppu/source/uno/IdentityMapping.cxx create mode 100644 cppu/source/uno/IdentityMapping.hxx create mode 100644 cppu/source/uno/any.cxx create mode 100644 cppu/source/uno/assign.hxx create mode 100644 cppu/source/uno/cascade_mapping.cxx create mode 100644 cppu/source/uno/cascade_mapping.hxx create mode 100644 cppu/source/uno/check.cxx create mode 100644 cppu/source/uno/constr.hxx create mode 100644 cppu/source/uno/copy.hxx create mode 100644 cppu/source/uno/data.cxx create mode 100644 cppu/source/uno/destr.hxx create mode 100644 cppu/source/uno/eq.hxx create mode 100644 cppu/source/uno/lbenv.cxx create mode 100644 cppu/source/uno/lbmap.cxx create mode 100644 cppu/source/uno/loadmodule.cxx create mode 100644 cppu/source/uno/loadmodule.hxx create mode 100644 cppu/source/uno/prim.hxx create mode 100644 cppu/source/uno/sequence.cxx (limited to 'cppu/source') 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +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 m_pInnerThread; + osl::Condition m_innerCondition; + sal_Int32 m_enterCount; + + osl::Mutex m_outerMutex; + oslThreadIdentifier m_outerThreadId; + osl::Condition m_outerCondition; + std::unique_ptr 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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(pArg)); + break; + case typelib_TypeClass_BYTE: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_CHAR: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_FLOAT: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_DOUBLE: + SAL_INFO("cppu.log", "" << *static_cast(pArg)); + break; + case typelib_TypeClass_TYPE: + SAL_INFO("cppu.log", "" << static_cast(pArg)->getTypeName()); + break; + case typelib_TypeClass_ANY: + if ( static_cast(pArg)->pData ) + traceValue(static_cast(pArg)->pType,static_cast(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 +#include +#include +#include + +#include +#include +#include + +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 + +#include + +#include +#include +#include + +// 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 + +#include +#include +#include +#include + + +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 + +#include +#include +#include + +#include + + +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 + +#include +#include +#include +#include + +#include +#include +#include + +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 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(pEnv->pReserved); + pBase->acquire(); +} + +static void s_release(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast(pEnv->pReserved); + pBase->release(); +} + +static void s_harden(uno_Environment ** ppHardEnv, uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast(pEnv->pReserved); + pBase->harden(ppHardEnv); +} + +static void s_acquireWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast(pEnv->pReserved); + pBase->acquireWeak(); +} + +static void s_releaseWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast(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(pExtEnv->aBase.pReserved); + pBase->registerProxyInterface(ppProxy, freeProxy, pOId, pTypeDescr); +} + +static void s_revokeInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) +{ + Base * pBase = static_cast(pExtEnv->aBase.pReserved); + pBase->revokeInterface(pInterface); +} + +static void s_getObjectIdentifier(uno_ExtEnvironment * pExtEnv, + rtl_uString ** ppOId, + void * pInterface) +{ + Base * pBase = static_cast(pExtEnv->aBase.pReserved); + pBase->getObjectIdentifier(pInterface, reinterpret_cast(ppOId)); +} + +static void s_getRegisteredInterface(uno_ExtEnvironment * pExtEnv, + void ** ppInterface, + rtl_uString * pOId, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + Base * pBase = static_cast(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(pExtEnv->aBase.pReserved); + pBase->getRegisteredInterfaces(pppInterface, pnLen, memAlloc); +} + +static void s_computeObjectIdentifier(uno_ExtEnvironment * pExtEnv, + rtl_uString ** ppOId, + void * pInterface) +{ + Base * pBase = static_cast(pExtEnv->aBase.pReserved); + pBase->computeObjectIdentifier(pInterface, reinterpret_cast(ppOId)); +} + +static void s_acquireInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) { + Base * pBase = static_cast(pExtEnv->aBase.pReserved); + pBase->acquireInterface(pInterface); +} + +static void s_releaseInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) { + Base * pBase = static_cast(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(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(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 + +#include "Proxy.hxx" + +#include +#include +#include +#include + +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(puno_Mapping); + pMapping->mapInterface( + reinterpret_cast(ppOut), + static_cast(pUnoI), pTypeDescr); +} + +extern "C" { +static void s_acquire(uno_Mapping * puno_Mapping) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast(puno_Mapping); + pMapping->acquire(); +} + +static void s_release(uno_Mapping * puno_Mapping) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast(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(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(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(&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 +#include +#include +#include + +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(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(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(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(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( + pMemberType)->pAttributeTypeRef; + nParams = 0; + pParams = nullptr; + } + else + { + param.pTypeRef = reinterpret_cast( + pMemberType)->pAttributeTypeRef; + param.bIn = true; + param.bOut = false; + nParams = 1; + pParams = ¶m; + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const * method_td = + reinterpret_cast(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(static_cast(pProxy)); + delete pThis; +} + +extern "C" { +static void s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C() +{ + Proxy * pProxy = static_cast(pUnoI); + pProxy->acquire(); +} + +static void s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C() +{ + Proxy * pProxy = static_cast(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(&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(&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(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 + +#include +#include + +#include +#include +#include +#include + +#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(&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(&pMethod)); + typelib_typedescription_release(&pMethod->aBase.aBase); + // another static ref: + ++reinterpret_cast(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 + +#include + +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 + +#include + +#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 + +#include +#include +#include +#include + +#include + +namespace cppu_threadpool +{ + extern "C" typedef void (RequestFun)(void *); + + struct Job + { + void *pThreadSpecificData; + RequestFun * doRequest; + }; + + class DisposedCallerAdmin; + typedef std::shared_ptr 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 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 + +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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 +#include + +#include +#include + +#include + +#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(&(*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 + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "threadpool.hxx" +#include "thread.hxx" + +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; + +namespace cppu_threadpool +{ + WaitingThread::WaitingThread( + rtl::Reference theThread): thread(std::move(theThread)) + {} + + DisposedCallerAdminHolder const & DisposedCallerAdmin::getInstance() + { + static DisposedCallerAdminHolder theDisposedCallerAdmin = std::make_shared(); + 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( 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 +#include +#include + +#include +#include +#include +#include +#include + +#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(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 theThread); + }; + + typedef std::deque< struct ::cppu_threadpool::WaitingThread * > WaitingThreadDeque; + + class DisposedCallerAdmin; + typedef std::shared_ptr 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 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 + +#include +#include + +#include +#include + +#include +#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( reinterpret_cast(&reinterpret_cast(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(&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(&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(&pMethod) ); + + ::typelib_typedescription_newInterfaceMethod( + &pMethod, 2, true, sMethodName2.pData, + typelib_TypeClass_VOID, sReturnType1.pData, + 0, nullptr, 0, nullptr ); + ::typelib_typedescription_register( reinterpret_cast(&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(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(&pComp), eTypeClass, aTypeName.pData ); + + sal_Int32 nOffset = 0; + if (pBaseType) + { + ::typelib_typedescriptionreference_getDescription( + reinterpret_cast(&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(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(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(&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(&pIface->ppBaseTypes[i]), ppBaseTypes[i] ); + assert( pIface->ppBaseTypes[i] ); + } + } + else + { + pIface->ppBaseTypes[0] = nullptr; + ::typelib_typedescriptionreference_getDescription( + reinterpret_cast(&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(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(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(pReg); + + pEnum->nDefaultEnumValue = nDefaultValue; + + pReg->pWeakRef = reinterpret_cast(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(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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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( reinterpret_cast(&reinterpret_cast(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(pTD); + + std::vector 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(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 T * allocTypeDescription() { + return reinterpret_cast(new char[sizeof (T)]); +} + +void freeTypeDescription(typelib_TypeDescription const * desc) { + delete[] reinterpret_cast(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(*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(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(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(); + 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(); + 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(); + 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(); + 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(); +#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(*ppRet)->pType = pType; + } + break; + + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + { + // FEATURE_EMPTYCLASS + typelib_CompoundTypeDescription * pTmp = reinterpret_cast(*ppRet); + + sal_Int32 nOffset = 0; + if( pType ) + { + typelib_typedescriptionreference_getDescription( + reinterpret_cast(&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 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(*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(*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(*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(&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(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(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(*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(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(*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(pTD)->pType ) + typelib_typedescriptionreference_release( reinterpret_cast(pTD)->pType ); + break; + case typelib_TypeClass_STRUCT: + delete[] reinterpret_cast< typelib_StructTypeDescription * >(pTD)-> + pParameterizedTypes; + [[fallthrough]]; + case typelib_TypeClass_EXCEPTION: + { + typelib_CompoundTypeDescription * pCTD = reinterpret_cast(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(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(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(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(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((*aIt).second) == static_cast(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(pTDR) != static_cast(*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(pTDR->pType)->ppAllMembers && + (*reinterpret_cast(ppNewDescription))->ppAllMembers))) + { + // uninitialized or incomplete + + if (pTDR->pType->pWeakRef) // if init + { + switch (pTDR->pType->eTypeClass) { + case typelib_TypeClass_ENUM: + { + auto const src = reinterpret_cast( + *ppNewDescription); + auto const dst = reinterpret_cast( + 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( + *ppNewDescription); + auto const dst = reinterpret_cast( + 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( + dst)->pParameterizedTypes + == nullptr) + == (reinterpret_cast( + src)->pParameterizedTypes + == nullptr))); + std::swap(src->ppMemberNames, dst->ppMemberNames); + break; + } + case typelib_TypeClass_INTERFACE: + { + auto const src = reinterpret_cast( + *ppNewDescription); + auto const dst = reinterpret_cast( + 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(*ppNewDescription); + + // description is the weak itself, so register it + rInit.maWeakMap[pTDR->pTypeName->buffer] = pTDR; + OSL_ASSERT( static_cast(*ppNewDescription) == static_cast(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(p1), reinterpret_cast(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(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(*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(pRet)->pType ); + if (*ppTDR) + typelib_typedescriptionreference_release( *ppTDR ); + *ppTDR = reinterpret_cast(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(ppTDR), eTypeClass, pTypeName ); + // description will be registered but not acquired + (*reinterpret_cast(ppTDR))->bOnDemand = true; + (*reinterpret_cast(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(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(pRef)->nRefCount ); + *ppRet = reinterpret_cast(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(pFromDescr)->pBaseTypeDescription) + { + TYPELIB_DANGER_RELEASE( pFromDescr ); + return false; + } + bool bRet = typelib_typedescriptionreference_isAssignableFrom( + pAssignable, + reinterpret_cast(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 +#include +#include +#include + +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 + + +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 +#include + +#include +#include + +#include +#include +#include + +#include +#include + +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 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(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, ¶m); + va_end(param); +} + +static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam) +{ + cppu::Enterable * pEnterable = static_cast(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, ¶m); + 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, ¶m); + 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(pCurrEnv->pReserved); + if (pEnterable) + pEnterable->leave(); + pCurrEnv->release(pCurrEnv); + break; + + case 1: + pNextEnv->acquire(pNextEnv); + pEnterable = static_cast(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(pEnv->pReserved); + if (pEnterable) + result = pEnterable->isValid(reinterpret_cast(pReason)); + } + else + { + OUString envDcp = UNO_LB_UNO + cppu::EnvDcp::getPurpose(pEnv->pTypeName); + + uno::Environment env(envDcp); + + result = env.isValid(reinterpret_cast(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 +#include +#include +#include + +#include + + +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(pMapping); +} + +static void s_acquire(uno_Mapping * pMapping) +{ + static OUString s_purpose; + + if (1 == osl_atomic_increment(&static_cast(pMapping)->m_nRef)) + { + uno_registerMapping( + &pMapping, + s_free, + static_cast(pMapping)->m_env.get(), + static_cast(pMapping)->m_env.get(), + s_purpose.pData); + } +} + +static void s_release(uno_Mapping * pMapping) +{ + if (!osl_atomic_decrement(&static_cast(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(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 + +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(pDest) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], + static_cast(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(pSource)->pType; + pSource = static_cast(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(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_BOOLEAN: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BOOLEAN: + *static_cast(pDest) = bool(*static_cast(pSource)); + return true; + default: + return false; + } + case typelib_TypeClass_BYTE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_SHORT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_SHORT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_LONG: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_LONG: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_HYPER: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_HYPER: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_FLOAT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_FLOAT: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_DOUBLE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_FLOAT: + *static_cast(pDest) = *static_cast(pSource); + return true; + case typelib_TypeClass_DOUBLE: + *static_cast(pDest) = *static_cast(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_STRING: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_STRING: + ::rtl_uString_assign( static_cast(pDest), *static_cast(pSource) ); + return true; + default: + return false; + } + case typelib_TypeClass_TYPE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_TYPE: + { + typelib_TypeDescriptionReference ** pp = static_cast(pDest); + ::typelib_typedescriptionreference_release( *pp ); + *pp = *static_cast(pSource); + TYPE_ACQUIRE( *pp ); + return true; + } + default: + return false; + } + case typelib_TypeClass_ANY: + _destructAny( static_cast(pDest), release ); + _copyConstructAny( static_cast(pDest), pSource, pSourceType, pSourceTypeDescr, acquire, nullptr ); + return true; + case typelib_TypeClass_ENUM: + if (_type_equals( pDestType, pSourceType )) + { + *static_cast(pDest) = *static_cast(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(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(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(pSource) != *static_cast(pDest)) + { + osl_atomic_increment( &(*static_cast(pSource))->nRefCount ); + idestructSequence( + *static_cast(pDest), pDestType, pDestTypeDescr, release ); + *static_cast(pDest) = *static_cast(pSource); + } + return true; + case typelib_TypeClass_INTERFACE: + if (typelib_TypeClass_INTERFACE != pSourceType->eTypeClass) + return false; + if (_type_equals( pDestType, pSourceType )) + { + _assignInterface( static_cast(pDest), *static_cast(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(pTD)->pBaseTypeDescription->aBase; + } + if (pTD) // is base of dest + { + _assignInterface( static_cast(pDest), *static_cast(pSource), acquire, release ); + return true; + } + } + + // query for interface: + void * pQueried = _queryInterface( *static_cast(pSource), + pDestType, queryInterface ); + if (pQueried != nullptr) { + void * const pToBeReleased = *static_cast(pDest); + *static_cast(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 +#include +#include +#include +#include +#include +#include + +#include + +#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(mapping); + pMediatorMapping->acquire(); +} + +static void s_release(uno_Mapping * mapping) +{ + MediatorMapping * pMediatorMapping = static_cast(mapping); + pMediatorMapping->release(); +} + +static void s_mapInterface( + uno_Mapping * mapping, + void ** ppOut, + void * pInterface, + typelib_InterfaceTypeDescription * pInterfaceTypeDescr) +{ + MediatorMapping * pMediatorMapping = static_cast(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(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) // -> 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 -> ? + // 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 +#include +#include + + +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 + +#include + +#include +#include +#include +#include + + +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(true) == sal_True, + "must be binary compatible" ); +// [-loplugin:fakebool] false positive: +static_assert( static_cast(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 std::size_t OFFSET_OF(T2 T1::* p) { + return reinterpret_cast< size_t >(reinterpret_cast(&(reinterpret_cast(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 + +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(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(pMem) = '\0'; + break; + case typelib_TypeClass_BOOLEAN: + *static_cast(pMem) = false; + break; + case typelib_TypeClass_BYTE: + *static_cast(pMem) = 0; + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pMem) = 0; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pMem) = 0; + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast(pMem) = 0; + break; + case typelib_TypeClass_FLOAT: + *static_cast(pMem) = 0.0; + break; + case typelib_TypeClass_DOUBLE: + *static_cast(pMem) = 0.0; + break; + case typelib_TypeClass_STRING: + *static_cast(pMem) = nullptr; + ::rtl_uString_new( static_cast(pMem) ); + break; + case typelib_TypeClass_TYPE: + *static_cast(pMem) = _getVoidType(); + break; + case typelib_TypeClass_ANY: + CONSTRUCT_EMPTY_ANY( static_cast(pMem) ); + break; + case typelib_TypeClass_ENUM: + if (pTypeDescr) + { + *static_cast(pMem) = reinterpret_cast(pTypeDescr)->nDefaultEnumValue; + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast(pMem) = reinterpret_cast(pTypeDescr)->nDefaultEnumValue; + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + _defaultConstructStruct( pMem, reinterpret_cast(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _defaultConstructStruct( pMem, reinterpret_cast(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + *static_cast(pMem) = createEmptySequence(); + break; + case typelib_TypeClass_INTERFACE: + *static_cast(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 +#include +#include +#include + +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); +static_assert(offsetof(SequencePrefix, nElements) == offsetof(uno_Sequence, nElements)); +static_assert( + std::is_same_v); + +} + +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(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(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(pDest) + pMemberOffsets[nDescr], + static_cast(pSource) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], mapping ); + } + } + else + { + while (nDescr--) + { + ::uno_type_copyData( + static_cast(pDest) + pMemberOffsets[nDescr], + static_cast(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(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_BOOLEAN: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = bool(*static_cast(pSource)); + break; + case typelib_TypeClass_BYTE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = *static_cast(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(pDestAny->pData) = *static_cast(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(pDestAny->pData) = *static_cast(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(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_STRING: + ::rtl_uString_acquire( *static_cast(pSource) ); + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_TYPE: + TYPE_ACQUIRE( *static_cast(pSource) ); + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = *static_cast(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(pDestAny->pData) = *static_cast(pSource); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _copyConstructStruct( + pDestAny->pData, pSource, + reinterpret_cast(pTypeDescr), + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _copyConstructStruct( + pDestAny->pData, pSource, + reinterpret_cast(pTypeDescr), + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + pDestAny->pData = &pDestAny->pReserved; + if (pTypeDescr) + { + *static_cast(pDestAny->pData) = copyConstructSequence( + *static_cast(pSource), + reinterpret_cast(pTypeDescr)->pType, + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast(pDestAny->pData) = copyConstructSequence( + *static_cast(pSource), + reinterpret_cast(pTypeDescr)->pType, + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_INTERFACE: + pDestAny->pData = &pDestAny->pReserved; + if (mapping) + { + pDestAny->pReserved = _map( *static_cast(pSource), pType, pTypeDescr, mapping ); + } + else + { + pDestAny->pReserved = *static_cast(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(pSource)->pType; + if (typelib_TypeClass_VOID == pType->eTypeClass) + { + CONSTRUCT_EMPTY_ANY( pDestAny ); + return; + } + pTypeDescr = nullptr; + pSource = static_cast(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(pDestAny->pData) = '\0'; + break; + case typelib_TypeClass_BOOLEAN: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = false; + break; + case typelib_TypeClass_BYTE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = 0; + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = 0; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(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(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(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(pDestAny->pData) = 0.0; + break; + case typelib_TypeClass_STRING: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = nullptr; + ::rtl_uString_new( static_cast(pDestAny->pData) ); + break; + case typelib_TypeClass_TYPE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(pDestAny->pData) = _getVoidType(); + break; + case typelib_TypeClass_ENUM: + pDestAny->pData = &pDestAny->pReserved; + if (pTypeDescr) + { + *static_cast(pDestAny->pData) = reinterpret_cast(pTypeDescr)->nDefaultEnumValue; + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast(pDestAny->pData) = reinterpret_cast(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(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _defaultConstructStruct( + pDestAny->pData, reinterpret_cast(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast(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(pDest->elements); + uno_Any * pSourceElements = reinterpret_cast(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( + 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( + pElementTypeDescr)->pType; + + uno_Sequence ** pDestElements = + reinterpret_cast(pDest->elements); + uno_Sequence ** pSourceElements = + reinterpret_cast(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(pSource->elements); + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + for ( sal_Int32 nPos = nElements; nPos--; ) + { + reinterpret_cast(pElements)[nPos] = nullptr; + if (pSourceElements[nPos]) + { + (*mapping->mapInterface)( + mapping, reinterpret_cast(pElements) + nPos, + pSourceElements[nPos], + reinterpret_cast( + 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(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_BOOLEAN: + *static_cast(pDest) = bool(*static_cast(pSource)); + break; + case typelib_TypeClass_BYTE: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_FLOAT: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_DOUBLE: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_STRING: + ::rtl_uString_acquire( *static_cast(pSource) ); + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_TYPE: + TYPE_ACQUIRE( *static_cast(pSource) ); + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_ANY: + _copyConstructAny( + static_cast(pDest), static_cast(pSource)->pData, + static_cast(pSource)->pType, nullptr, + acquire, mapping ); + break; + case typelib_TypeClass_ENUM: + *static_cast(pDest) = *static_cast(pSource); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + _copyConstructStruct( + pDest, pSource, + reinterpret_cast(pTypeDescr), + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _copyConstructStruct( + pDest, pSource, + reinterpret_cast(pTypeDescr), + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + if (mapping) + { + if (pTypeDescr) + { + *static_cast(pDest) = icopyConstructSequence( + *static_cast(pSource), + reinterpret_cast(pTypeDescr)->pType, + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast(pDest) = icopyConstructSequence( + *static_cast(pSource), + reinterpret_cast(pTypeDescr)->pType, + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + } + else + { + osl_atomic_increment( &(*static_cast(pSource))->nRefCount ); + *static_cast(pDest) = *static_cast(pSource); + } + break; + case typelib_TypeClass_INTERFACE: + if (mapping) + *static_cast(pDest) = _map( *static_cast(pSource), pType, pTypeDescr, mapping ); + else + { + *static_cast(pDest) = *static_cast(pSource); + _acquire( *static_cast(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 +#include + +#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(&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(pUnoI)->pDispatcher)( + static_cast(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(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(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(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 +#include + +#include +#include + +#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(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(pAny->pReserved) ); + break; + case typelib_TypeClass_TYPE: + ::typelib_typedescriptionreference_release( + static_cast(pAny->pReserved) ); + break; + case typelib_TypeClass_ANY: + OSL_FAIL( "### unexpected nested any!" ); + ::uno_any_destruct( static_cast(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(pTypeDescr), release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + std::free( pAny->pData ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + destructSequence( + static_cast(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(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(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(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(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(pElements) + (nElementSize * nPos), + reinterpret_cast(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(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(pElements)[nPos]; + if (p) + { + (*release)( p ); + } + } + } + else + { + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + uno_Interface * p = static_cast(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(pTypeDescr)->pType, 0, + pSeq->nElements, release ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + idestructElements( + pSeq->elements, + reinterpret_cast(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(pValue) ); + break; + case typelib_TypeClass_TYPE: + ::typelib_typedescriptionreference_release( *static_cast(pValue) ); + break; + case typelib_TypeClass_ANY: + _destructAny( static_cast(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(pTypeDescr), release ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _destructStruct( pValue, reinterpret_cast(pTypeDescr), release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + { + idestructSequence( + *static_cast(pValue), pType, pTypeDescr, release ); + break; + } + case typelib_TypeClass_INTERFACE: + _release( *static_cast(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 +#include + +#include +#include +#include + +#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(pDest) + nOffset, + ppTypeRefs[nDescr], + static_cast(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(pDestElements)[nPos]) != + bool(static_cast(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(pDestElements)[nPos] != static_cast(pSourceElements)[nPos]) + return false; + } + return true; + } + case typelib_TypeClass_DOUBLE: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (static_cast(pDestElements)[nPos] != static_cast(pSourceElements)[nPos]) + return false; + } + return true; + } + case typelib_TypeClass_STRING: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if ( static_cast(pDestElements)[nPos] != static_cast(pSourceElements)[nPos] ) + return false; + } + return true; + } + case typelib_TypeClass_TYPE: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! _type_equals( static_cast(pDestElements)[nPos], + static_cast(pSourceElements)[nPos] )) + { + return false; + } + } + return true; + } + case typelib_TypeClass_ANY: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + uno_Any * pDest2 = static_cast(pDestElements) + nPos; + uno_Any * pSource2 = static_cast(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(pDestElements) + (nPos * nElementSize), + static_cast(pSourceElements) + (nPos * nElementSize), + reinterpret_cast(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(pElementTypeDescr)->pType; + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! equalSequence( static_cast(pDestElements)[nPos], + static_cast(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(pDestElements)[nPos], static_cast(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(pDest)->pType; + pDest = static_cast(pDest)->pData; + } + while (typelib_TypeClass_ANY == (eSourceTypeClass = pSourceType->eTypeClass)) + { + pSourceType = static_cast(pSource)->pType; + pSource = static_cast(pSource)->pData; + } + + switch (eDestTypeClass) + { + case typelib_TypeClass_VOID: + return eSourceTypeClass == typelib_TypeClass_VOID; + case typelib_TypeClass_CHAR: + return eSourceTypeClass == typelib_TypeClass_CHAR + && *static_cast(pDest) == *static_cast(pSource); + case typelib_TypeClass_BOOLEAN: + return eSourceTypeClass == typelib_TypeClass_BOOLEAN + && (bool(*static_cast(pDest)) + == bool(*static_cast(pSource))); + case typelib_TypeClass_BYTE: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_SHORT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_SHORT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_LONG: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_LONG: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_HYPER: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_HYPER: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return o3tl::cmp_equal( + *static_cast(pDest), *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + if (::floor( *static_cast(pSource) ) != *static_cast(pSource) || *static_cast(pSource) < 0) + return false; + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_DOUBLE: + if (::floor( *static_cast(pSource) ) != *static_cast(pSource) || *static_cast(pSource) < 0) + return false; + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + default: + return false; + } + case typelib_TypeClass_FLOAT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_HYPER: + if (::floor( *static_cast(pDest) ) != *static_cast(pDest) || *static_cast(pDest) < 0) + return false; + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (*static_cast(pDest) == *static_cast(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_DOUBLE: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_UNSIGNED_HYPER: + if (::floor( *static_cast(pDest) ) != *static_cast(pDest) || *static_cast(pDest) < 0) + return false; + return (static_cast(*static_cast(pDest)) == *static_cast(pSource)); + case typelib_TypeClass_FLOAT: + return (*static_cast(pDest) == static_cast(*static_cast(pSource))); + case typelib_TypeClass_DOUBLE: + return (*static_cast(pDest) == *static_cast(pSource)); + default: + return false; + } + case typelib_TypeClass_STRING: + return eSourceTypeClass == typelib_TypeClass_STRING + && *static_cast(pDest) == + *static_cast(pSource); + case typelib_TypeClass_TYPE: + return eSourceTypeClass == typelib_TypeClass_TYPE + && _type_equals( + *static_cast(pDest), + *static_cast(pSource) ); + case typelib_TypeClass_ENUM: + return (_type_equals( pDestType, pSourceType ) && + *static_cast(pDest) == *static_cast(pSource)); + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (! _type_equals( pDestType, pSourceType )) + return false; + if (pDestTypeDescr) + { + return _equalStruct( + pDest, pSource, + reinterpret_cast(pDestTypeDescr), + queryInterface, release ); + } + else + { + TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType ); + bool bRet = _equalStruct( + pDest, pSource, + reinterpret_cast(pDestTypeDescr), + queryInterface, release ); + TYPELIB_DANGER_RELEASE( pDestTypeDescr ); + return bRet; + } + case typelib_TypeClass_SEQUENCE: + if (_type_equals( pDestType, pSourceType )) + { + if (pDestTypeDescr) + { + return _equalSequence( + *static_cast(pDest), *static_cast(pSource), + reinterpret_cast(pDestTypeDescr)->pType, + queryInterface, release ); + } + else + { + TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType ); + bool bRet = _equalSequence( + *static_cast(pDest), *static_cast(pSource), + reinterpret_cast(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(pDest), *static_cast(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 +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "prim.hxx" +#include "loadmodule.hxx" + +#include +#include +#include +#include +#include + + +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 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 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((*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(pEnv); + osl_atomic_increment( &that->nWeakRef ); + osl_atomic_increment( &that->nRef ); +} + + +static void defenv_release( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast(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(pEnv); + osl_atomic_increment( &that->nWeakRef ); +} + + +static void defenv_releaseWeak( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast(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(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(stream), "%s\n", pLine ); + } + else + { + SAL_WARN("cppu", pLine ); + } + } + } + ++pLine; + } + } + else + { + if (stream) + { + fprintf( static_cast(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(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(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( + ::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 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((*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(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(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 +#endif + +#include "IdentityMapping.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#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(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 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(&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(aModule.getSymbol( UNO_EXT_GETMAPPING )); + + if (fpGetMapFunc) + { + Mapping aExt; + (*fpGetMapFunc)( reinterpret_cast(&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(&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(&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 + +#include + +#include +#include +#include +#include +#include +#include + +#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(&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 +#include + +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 +#include +#include +#include +#include +#include +#include + +#include +#include + +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(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + (*mapping->mapInterface)( + mapping, &pRet, p, reinterpret_cast(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + } + return pRet; +} + +inline void _acquire( void * p, uno_AcquireFunc acquire ) +{ + if (p) + { + if (acquire) + { + (*acquire)( p ); + } + else + { + (*static_cast(p)->acquire)( static_cast(p) ); + } + } +} + +inline void _release( void * p, uno_ReleaseFunc release ) +{ + if (p) + { + if (release) + { + (*release)( p ); + } + else + { + (*static_cast(p)->release)( static_cast(p) ); + } + } +} + + +inline sal_uInt32 calcSeqMemSize( + sal_Int32 nElementSize, sal_Int32 nElements ) +{ + sal_uInt64 nSize = + static_cast(SAL_SEQUENCE_HEADER_SIZE) + + (static_cast(nElementSize) * static_cast(nElements)); + if (nSize > 0xffffffffU) + return 0; + else + return static_cast(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(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 + +#include +#include + +#include +#include +#include +#include +#include + +#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(std::malloc( nSize )); + } + else + { + pNew = static_cast(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(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(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(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(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(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( + pElementTypeDescr)->nDefaultEnumValue; + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + + sal_Int32 * pElements = reinterpret_cast(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(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(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(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(pSourceElements)[nPos] ); + pDestElements[nPos] = static_cast(pSourceElements)[nPos]; + } + } + break; + } + case typelib_TypeClass_TYPE: + { + pSeq = reallocSeq( + pSeq, sizeof(typelib_TypeDescriptionReference *), nAlloc ); + if (pSeq != nullptr) + { + typelib_TypeDescriptionReference ** pDestElements = + reinterpret_cast(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + TYPE_ACQUIRE( + static_cast( + pSourceElements)[nPos] ); + pDestElements[nPos] = + static_cast( + pSourceElements)[nPos]; + } + } + break; + } + case typelib_TypeClass_ANY: + { + pSeq = reallocSeq( pSeq, sizeof(uno_Any), nAlloc ); + if (pSeq != nullptr) + { + uno_Any * pDestElements = reinterpret_cast(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + uno_Any * pSource = static_cast(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(pElementTypeDescr); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + char * pDest = + pDestElements + (nElementSize * nPos); + char * pSource = + static_cast(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(pElementTypeDescr)->pType; + uno_Sequence ** pDestElements = reinterpret_cast(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + uno_Sequence * pNew = icopyConstructSequence( + static_cast(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(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + pDestElements[nPos] = static_cast(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(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(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(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(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(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(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: */ -- cgit v1.2.3