/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifdef DISABLE_DYNLOADING
#include <config_java.h>
#endif
#include <cppu/EnvDcp.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <osl/interlck.h>
#include <osl/mutex.hxx>
#include <osl/module.hxx>
#include <osl/process.h>
#include <rtl/process.h>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <typelib/typedescription.h>
#include <uno/dispatcher.h>
#include <uno/environment.h>
#include <uno/lbnames.h>
#include "prim.hxx"
#include "loadmodule.hxx"
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
#include <stdio.h>
namespace
{
bool td_equals( typelib_InterfaceTypeDescription const * pTD1,
typelib_InterfaceTypeDescription const * pTD2 )
{
return (pTD1 == pTD2 ||
(pTD1->aBase.pTypeName->length == pTD2->aBase.pTypeName->length &&
::rtl_ustr_compare(
pTD1->aBase.pTypeName->buffer,
pTD2->aBase.pTypeName->buffer ) == 0));
}
struct uno_DefaultEnvironment;
struct InterfaceEntry
{
sal_Int32 refCount;
void * pInterface;
uno_freeProxyFunc fpFreeProxy;
typelib_InterfaceTypeDescription * pTypeDescr;
};
struct ObjectEntry
{
OUString oid;
std::vector< InterfaceEntry > aInterfaces;
sal_Int32 nRef;
bool mixedObject;
explicit ObjectEntry( OUString aOId_ );
void append(
uno_DefaultEnvironment * pEnv,
void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
uno_freeProxyFunc fpFreeProxy );
InterfaceEntry * find(
typelib_InterfaceTypeDescription * pTypeDescr );
sal_Int32 find( void const * iface_ptr, std::size_t pos ) const;
};
struct FctPtrHash
{
std::size_t operator () ( const void * pKey ) const
{ return reinterpret_cast< std::size_t>( pKey ); }
};
// mapping from environment name to environment
typedef std::unordered_map<
OUString, uno_Environment * > OUString2EnvironmentMap;
// mapping from ptr to object entry
typedef std::unordered_map<
void *, ObjectEntry *, FctPtrHash > Ptr2ObjectMap;
// mapping from oid to object entry
typedef std::unordered_map<
OUString, ObjectEntry * > OId2ObjectMap;
struct EnvironmentsData
{
::osl::Mutex mutex;
OUString2EnvironmentMap aName2EnvMap;
EnvironmentsData() : isDisposing(false) {}
~EnvironmentsData();
void getEnvironment(
uno_Environment ** ppEnv, std::u16string_view rEnvDcp, void * pContext );
void registerEnvironment( uno_Environment ** ppEnv );
void getRegisteredEnvironments(
uno_Environment *** pppEnvs, sal_Int32 * pnLen,
uno_memAlloc memAlloc, std::u16string_view rEnvDcp );
bool isDisposing;
};
EnvironmentsData& theEnvironmentsData()
{
static EnvironmentsData SINGLETON;
return SINGLETON;
}
struct uno_DefaultEnvironment : public uno_ExtEnvironment
{
sal_Int32 nRef;
sal_Int32 nWeakRef;
::osl::Mutex mutex;
Ptr2ObjectMap aPtr2ObjectMap;
OId2ObjectMap aOId2ObjectMap;
uno_DefaultEnvironment(
const OUString & rEnvDcp_, void * pContext_ );
~uno_DefaultEnvironment();
};
ObjectEntry::ObjectEntry( OUString aOId_ )
: oid(std::move( aOId_ )),
nRef( 0 ),
mixedObject( false )
{
aInterfaces.reserve( 2 );
}
void ObjectEntry::append(
uno_DefaultEnvironment * pEnv,
void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
uno_freeProxyFunc fpFreeProxy )
{
InterfaceEntry aNewEntry;
if (! fpFreeProxy)
(*pEnv->acquireInterface)( pEnv, pInterface );
aNewEntry.refCount = 1;
aNewEntry.pInterface = pInterface;
aNewEntry.fpFreeProxy = fpFreeProxy;
typelib_typedescription_acquire( &pTypeDescr->aBase );
aNewEntry.pTypeDescr = pTypeDescr;
std::pair< Ptr2ObjectMap::iterator, bool > i(
pEnv->aPtr2ObjectMap.emplace( pInterface, this ) );
SAL_WARN_IF(
!i.second && (find(pInterface, 0) == -1 || i.first->second != this),
"cppu",
"map already contains " << i.first->second << " != " << this << " for "
<< pInterface);
aInterfaces.push_back( aNewEntry );
}
InterfaceEntry * ObjectEntry::find(
typelib_InterfaceTypeDescription * pTypeDescr_ )
{
OSL_ASSERT( ! aInterfaces.empty() );
if (aInterfaces.empty())
return nullptr;
// shortcut common case:
OUString const & type_name =
OUString::unacquired( &pTypeDescr_->aBase.pTypeName );
if ( type_name == "com.sun.star.uno.XInterface" )
{
return aInterfaces.data();
}
std::size_t nSize = aInterfaces.size();
for ( std::size_t nPos = 0; nPos < nSize; ++nPos )
{
typelib_InterfaceTypeDescription * pITD =
aInterfaces[ nPos ].pTypeDescr;
while (pITD)
{
if (td_equals( pITD, pTypeDescr_ ))
return &aInterfaces[ nPos ];
pITD = pITD->pBaseTypeDescription;
}
}
return nullptr;
}
sal_Int32 ObjectEntry::find(
void const * iface_ptr, std::size_t pos ) const
{
std::size_t size = aInterfaces.size();
for ( ; pos < size; ++pos )
{
if (aInterfaces[ pos ].pInterface == iface_ptr)
return pos;
}
return -1;
}
extern "C"
{
static void defenv_registerInterface(
uno_ExtEnvironment * pEnv, void ** ppInterface,
rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
{
assert(pEnv && ppInterface && pOId && pTypeDescr && "### null ptr!");
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
// try to insert dummy 0:
std::pair<OId2ObjectMap::iterator, bool> const insertion(
that->aOId2ObjectMap.emplace( rOId, nullptr ) );
if (insertion.second)
{
ObjectEntry * pOEntry = new ObjectEntry( rOId );
insertion.first->second = pOEntry;
++pOEntry->nRef; // another register call on object
pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
}
else // object entry exists
{
ObjectEntry * pOEntry = insertion.first->second;
++pOEntry->nRef; // another register call on object
InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
if (pIEntry) // type entry exists
{
++pIEntry->refCount;
if (pIEntry->pInterface != *ppInterface)
{
void * pInterface = pIEntry->pInterface;
(*pEnv->acquireInterface)( pEnv, pInterface );
guard.clear();
(*pEnv->releaseInterface)( pEnv, *ppInterface );
*ppInterface = pInterface;
}
}
else
{
pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
}
}
}
static void defenv_registerProxyInterface(
uno_ExtEnvironment * pEnv, void ** ppInterface, uno_freeProxyFunc freeProxy,
rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
{
assert(pEnv && ppInterface && pOId && pTypeDescr && freeProxy && "### null ptr!");
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
// try to insert dummy 0:
std::pair<OId2ObjectMap::iterator, bool> const insertion(
that->aOId2ObjectMap.emplace( rOId, nullptr ) );
if (insertion.second)
{
ObjectEntry * pOEntry = new ObjectEntry( rOId );
insertion.first->second = pOEntry;
++pOEntry->nRef; // another register call on object
pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
}
else // object entry exists
{
ObjectEntry * pOEntry = insertion.first->second;
// first registration was an original, then registerProxyInterface():
pOEntry->mixedObject |=
(!pOEntry->aInterfaces.empty() &&
pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr);
++pOEntry->nRef; // another register call on object
InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
if (pIEntry) // type entry exists
{
if (pIEntry->pInterface == *ppInterface)
{
++pIEntry->refCount;
}
else
{
void * pInterface = pIEntry->pInterface;
(*pEnv->acquireInterface)( pEnv, pInterface );
--pOEntry->nRef; // manual revoke of proxy to be freed
guard.clear();
(*freeProxy)( pEnv, *ppInterface );
*ppInterface = pInterface;
}
}
else
{
pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
}
}
}
static void s_stub_defenv_revokeInterface(va_list * pParam)
{
uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
void * pInterface = va_arg(*pParam, void *);
assert(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 ) );
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 )
{
assert(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 )
{
assert(pEnv && ppInterface && pOId && pTypeDescr && "### null ptr!");
if (*ppInterface)
{
(*pEnv->releaseInterface)( pEnv, *ppInterface );
*ppInterface = nullptr;
}
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::MutexGuard guard( that->mutex );
OId2ObjectMap::const_iterator const iFind
( that->aOId2ObjectMap.find( rOId ) );
if (iFind != that->aOId2ObjectMap.end())
{
InterfaceEntry const * pIEntry = iFind->second->find( pTypeDescr );
if (pIEntry)
{
(*pEnv->acquireInterface)( pEnv, pIEntry->pInterface );
*ppInterface = pIEntry->pInterface;
}
}
}
static void defenv_getRegisteredInterfaces(
uno_ExtEnvironment * pEnv, void *** pppInterfaces, sal_Int32 * pnLen,
uno_memAlloc memAlloc )
{
assert(pEnv && pppInterfaces && pnLen && memAlloc && "### null ptr!");
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::MutexGuard guard( that->mutex );
sal_Int32 nLen = that->aPtr2ObjectMap.size();
sal_Int32 nPos = 0;
void ** ppInterfaces = static_cast<void **>((*memAlloc)( nLen * sizeof (void *) ));
for (const auto& rEntry : that->aPtr2ObjectMap)
{
ppInterfaces[nPos] = rEntry.first;
(*pEnv->acquireInterface)( pEnv, ppInterfaces[nPos] );
nPos++;
}
*pppInterfaces = ppInterfaces;
*pnLen = nLen;
}
static void defenv_acquire( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
osl_atomic_increment( &that->nWeakRef );
osl_atomic_increment( &that->nRef );
}
static void defenv_release( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
if (! osl_atomic_decrement( &that->nRef ))
{
// invoke dispose callback
if (pEnv->environmentDisposing)
{
(*pEnv->environmentDisposing)( pEnv );
}
OSL_ENSURE( that->aOId2ObjectMap.empty(), "### object entries left!" );
}
// free memory if no weak refs left
if (! osl_atomic_decrement( &that->nWeakRef ))
{
delete that;
}
}
static void defenv_acquireWeak( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
osl_atomic_increment( &that->nWeakRef );
}
static void defenv_releaseWeak( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
if (! osl_atomic_decrement( &that->nWeakRef ))
{
delete that;
}
}
static void defenv_harden(
uno_Environment ** ppHardEnv, uno_Environment * pEnv )
{
if (*ppHardEnv)
{
(*(*ppHardEnv)->release)( *ppHardEnv );
*ppHardEnv = nullptr;
}
EnvironmentsData & rData = theEnvironmentsData();
if (rData.isDisposing)
return;
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
{
::osl::MutexGuard guard( rData.mutex );
if (1 == osl_atomic_increment( &that->nRef )) // is dead
{
that->nRef = 0;
return;
}
}
osl_atomic_increment( &that->nWeakRef );
*ppHardEnv = pEnv;
}
static void defenv_dispose( SAL_UNUSED_PARAMETER uno_Environment * )
{
}
}
uno_DefaultEnvironment::uno_DefaultEnvironment(
const OUString & rEnvDcp_, void * pContext_ )
: nRef( 0 ),
nWeakRef( 0 )
{
uno_Environment * that = reinterpret_cast< uno_Environment * >(this);
that->pReserved = nullptr;
// functions
that->acquire = defenv_acquire;
that->release = defenv_release;
that->acquireWeak = defenv_acquireWeak;
that->releaseWeak = defenv_releaseWeak;
that->harden = defenv_harden;
that->dispose = defenv_dispose;
that->pExtEnv = this;
// identifier
::rtl_uString_acquire( rEnvDcp_.pData );
that->pTypeName = rEnvDcp_.pData;
that->pContext = pContext_;
// will be late initialized
that->environmentDisposing = nullptr;
uno_ExtEnvironment::registerInterface = defenv_registerInterface;
uno_ExtEnvironment::registerProxyInterface = defenv_registerProxyInterface;
uno_ExtEnvironment::revokeInterface = defenv_revokeInterface;
uno_ExtEnvironment::getObjectIdentifier = defenv_getObjectIdentifier;
uno_ExtEnvironment::getRegisteredInterface = defenv_getRegisteredInterface;
uno_ExtEnvironment::getRegisteredInterfaces =
defenv_getRegisteredInterfaces;
}
uno_DefaultEnvironment::~uno_DefaultEnvironment()
{
::rtl_uString_release( aBase.pTypeName );
}
void writeLine(
void * stream, const char * pLine, const char * pFilter )
{
if (pFilter && *pFilter)
{
// lookup pFilter in pLine
while (*pLine)
{
if (*pLine == *pFilter)
{
sal_Int32 nPos = 1;
while (pLine[nPos] && pFilter[nPos] == pLine[nPos])
{
++nPos;
}
if (! pFilter[nPos])
{
if (stream)
{
fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
}
else
{
SAL_WARN("cppu", pLine );
}
}
}
++pLine;
}
}
else
{
if (stream)
{
fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
}
else
{
fprintf( stderr, "%s\n", pLine );
}
}
}
void writeLine(
void * stream, std::u16string_view rLine, const char * pFilter )
{
OString aLine( OUStringToOString(
rLine, RTL_TEXTENCODING_ASCII_US ) );
writeLine( stream, aLine.getStr(), pFilter );
}
}
extern "C" void SAL_CALL uno_dumpEnvironment(
void * stream, uno_Environment * pEnv, const char * pFilter ) noexcept
{
assert(pEnv && "### null ptr!");
OUStringBuffer buf;
if (! pEnv->pExtEnv)
{
writeLine( stream, "###################################"
"###########################################", pFilter );
buf.append( OUString::Concat("environment: ") + OUString::unacquired(&pEnv->pTypeName) );
writeLine( stream, buf, pFilter );
buf.setLength(0);
writeLine( stream, "NO INTERFACE INFORMATION AVAILABLE!", pFilter );
return;
}
writeLine( stream, "########################################"
"######################################", pFilter );
buf.append( OUString::Concat("environment dump: ") + OUString::unacquired(&pEnv->pTypeName) );
writeLine( stream, buf, pFilter );
buf.setLength(0);
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="
+ OUString::number(pOEntry->nRef)
+ "; oid=\""
+ pOEntry->oid
+ "\"" );
writeLine( stream, buf, pFilter );
buf.setLength(0);
for ( std::size_t nPos = 0;
nPos < pOEntry->aInterfaces.size(); ++nPos )
{
const InterfaceEntry & rIEntry = pOEntry->aInterfaces[nPos];
buf.append( OUString::Concat(" - ")
+ OUString::unacquired(&rIEntry.pTypeDescr->aBase.pTypeName) );
if (rIEntry.fpFreeProxy)
{
buf.append( "; proxy free=0x"
+ OUString::number( reinterpret_cast< sal_IntPtr >(rIEntry.fpFreeProxy), 16 ) );
}
else
{
buf.append( "; original" );
}
buf.append( "; ptr=0x"
+ OUString::number(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, pFilter );
buf.setLength(0);
}
}
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 ) noexcept
{
uno_Environment * pEnv = nullptr;
uno_getEnvironment( &pEnv, pEnvDcp, nullptr );
if (pEnv)
{
::uno_dumpEnvironment( stream, pEnv, pFilter );
(*pEnv->release)( pEnv );
}
else
{
writeLine(
stream,
Concat2View("environment \"" + OUString::unacquired(&pEnvDcp) + "\" does not exist!"),
pFilter );
}
}
namespace
{
const OUString & unoenv_getStaticOIdPart()
{
static auto const theStaticOIdPart = [] {
OUStringBuffer aRet( 64 );
aRet.append( "];" );
// pid
oslProcessInfo info;
info.Size = sizeof(oslProcessInfo);
if (::osl_getProcessInfo( nullptr, osl_Process_IDENTIFIER, &info ) ==
osl_Process_E_None)
{
aRet.append( static_cast<sal_Int64>(info.Ident), 16 );
}
else
{
aRet.append( "unknown process id" );
}
// good guid
sal_uInt8 ar[16];
::rtl_getGlobalProcessId( ar );
aRet.append( ';' );
for (unsigned char i : ar)
aRet.append( static_cast<sal_Int32>(i), 16 );
return aRet.makeStringAndClear();
}();
return theStaticOIdPart;
}
}
extern "C"
{
static void unoenv_computeObjectIdentifier(
uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
{
assert(pEnv && ppOId && pInterface && "### null ptr!");
if (*ppOId)
{
::rtl_uString_release( *ppOId );
*ppOId = nullptr;
}
uno_Interface * pUnoI = static_cast<uno_Interface *>(
::cppu::binuno_queryInterface(
pInterface, *typelib_static_type_getByTypeClass(
typelib_TypeClass_INTERFACE ) ));
if (nullptr == pUnoI)
return;
(*pUnoI->release)( pUnoI );
OUString aStr(
// interface
OUString::number( reinterpret_cast< sal_IntPtr >(pUnoI), 16 ) + ";"
// environment[context]
+ OUString::unacquired(&pEnv->aBase.pTypeName) + "["
+ OUString::number( reinterpret_cast< sal_IntPtr >(
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 )
{
assert(ppEnv && "### null ptr!");
uno_Environment * pEnv = *ppEnv;
OUString aKey =
OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->pContext) ) +
OUString::unacquired(&pEnv->pTypeName);
// try to find registered environment
OUString2EnvironmentMap::const_iterator const iFind(
aName2EnvMap.find( aKey ) );
if (iFind == aName2EnvMap.end())
{
(*pEnv->acquireWeak)( pEnv );
std::pair< OUString2EnvironmentMap::iterator, bool > insertion (
aName2EnvMap.emplace( aKey, pEnv ) );
SAL_WARN_IF( !insertion.second, "cppu", "key " << aKey << " already in env map" );
}
else
{
uno_Environment * pHard = nullptr;
uno_Environment * pWeak = iFind->second;
(*pWeak->harden)( &pHard, pWeak );
if (pHard)
{
(*pEnv->release)( pEnv );
*ppEnv = pHard;
}
else // registered one is dead
{
(*pWeak->releaseWeak)( pWeak );
(*pEnv->acquireWeak)( pEnv );
aName2EnvMap[ aKey ] = pEnv;
}
}
}
void EnvironmentsData::getRegisteredEnvironments(
uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
std::u16string_view rEnvDcp )
{
assert(pppEnvs && pnLen && memAlloc && "### null ptr!");
// max size
std::vector<uno_Environment*> aFounds(aName2EnvMap.size());
sal_Int32 nSize = 0;
// find matching environment
for ( const auto& rEntry : aName2EnvMap )
{
uno_Environment * pWeak = rEntry.second;
if (rEnvDcp.empty() ||
rEnvDcp == OUString::unacquired(&pWeak->pTypeName) )
{
aFounds[nSize] = nullptr;
(*pWeak->harden)( &aFounds[nSize], pWeak );
if (aFounds[nSize])
++nSize;
}
}
*pnLen = nSize;
if (nSize)
{
*pppEnvs = static_cast<uno_Environment **>((*memAlloc)(
sizeof (uno_Environment *) * nSize ));
OSL_ASSERT( *pppEnvs );
while (nSize--)
{
(*pppEnvs)[nSize] = aFounds[nSize];
}
}
else
{
*pppEnvs = nullptr;
}
}
bool loadEnv(OUString const & cLibStem,
uno_Environment * pEnv)
{
#ifdef DISABLE_DYNLOADING
uno_initEnvironmentFunc fpInit;
if ( cLibStem == CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" )
fpInit = CPPU_ENV_uno_initEnvironment;
#if HAVE_FEATURE_JAVA
else if ( cLibStem == "java_uno" )
fpInit = java_uno_initEnvironment;
#endif
else
{
SAL_INFO("cppu", ": Unhandled env: " << cLibStem);
return false;
}
#else
// late init with some code from matching uno language binding
// will be unloaded by environment
osl::Module aMod;
try {
bool bMod = cppu::detail::loadModule(aMod, cLibStem);
if (!bMod)
return false;
}
catch(...) {
// Catch everything and convert to return false
return false;
}
uno_initEnvironmentFunc fpInit = reinterpret_cast<uno_initEnvironmentFunc>(aMod.getSymbol(u"" UNO_INIT_ENVIRONMENT ""_ustr));
if (!fpInit)
return false;
aMod.release();
#endif
(*fpInit)( pEnv ); // init of environment
return true;
}
}
extern "C"
{
static uno_Environment * initDefaultEnvironment(
const OUString & rEnvDcp, void * pContext )
{
// coverity[leaked_storage : FALSE] - lifetime is controlled by acquire()/release() calls
uno_Environment * pEnv = &(new uno_DefaultEnvironment( rEnvDcp, pContext ))->aBase;
(*pEnv->acquire)( pEnv );
OUString envTypeName = cppu::EnvDcp::getTypeName(rEnvDcp);
// create default environment
if ( envTypeName == UNO_LB_UNO )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
that->computeObjectIdentifier = unoenv_computeObjectIdentifier;
that->acquireInterface = unoenv_acquireInterface;
that->releaseInterface = unoenv_releaseInterface;
OUString envPurpose = cppu::EnvDcp::getPurpose(rEnvDcp);
if (!envPurpose.isEmpty())
{
OUString libStem(
OUString::Concat(envPurpose.subView(envPurpose.lastIndexOf(':') + 1)) + "_uno_uno");
if(!loadEnv(libStem, pEnv))
{
pEnv->release(pEnv);
return nullptr;
}
}
}
else
{
// late init with some code from matching uno language binding
OUString aStr( envTypeName + "_uno" );
if (!loadEnv(aStr, pEnv))
{
pEnv->release(pEnv);
return nullptr;
}
}
return pEnv;
}
void SAL_CALL uno_createEnvironment(
uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext ) noexcept
{
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 ) noexcept
{
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 ) noexcept
{
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: */
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.