1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifdef DISABLE_DYNLOADING
21 #include <config_java.h>
24 #include "IdentityMapping.hxx"
29 #include <unordered_map>
32 #include <rtl/ustring.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <osl/module.hxx>
35 #include <osl/diagnose.h>
36 #include <osl/mutex.hxx>
37 #include <osl/interlck.h>
38 #include <sal/log.hxx>
40 #include <uno/dispatcher.h>
41 #include <uno/mapping.h>
42 #include <uno/lbnames.h>
43 #include <uno/environment.hxx>
45 #include <typelib/typedescription.h>
47 #include <cppu/EnvDcp.hxx>
48 #include "cascade_mapping.hxx"
49 #include "loadmodule.hxx"
52 using namespace com::sun::star::uno
;
61 uno_Mapping
* _pMapping
;
64 inline explicit Mapping( uno_Mapping
* pMapping
= nullptr );
65 inline Mapping( const Mapping
& rMapping
);
66 Mapping(Mapping
&& other
) noexcept
: _pMapping(other
._pMapping
)
67 { other
._pMapping
= nullptr; }
69 inline Mapping
& operator = ( uno_Mapping
* pMapping
);
70 Mapping
& operator = ( const Mapping
& rMapping
)
71 { return operator = ( rMapping
._pMapping
); }
72 Mapping
& operator =(Mapping
&& other
) noexcept
{
73 if (_pMapping
!= nullptr) {
74 (*_pMapping
->release
)(_pMapping
);
76 _pMapping
= other
._pMapping
;
77 other
._pMapping
= nullptr;
80 uno_Mapping
* get() const
83 { return (_pMapping
!= nullptr); }
88 inline Mapping::Mapping( uno_Mapping
* pMapping
)
89 : _pMapping( pMapping
)
92 (*_pMapping
->acquire
)( _pMapping
);
95 inline Mapping::Mapping( const Mapping
& rMapping
)
96 : _pMapping( rMapping
._pMapping
)
99 (*_pMapping
->acquire
)( _pMapping
);
102 inline Mapping::~Mapping()
105 (*_pMapping
->release
)( _pMapping
);
108 inline Mapping
& Mapping::operator = ( uno_Mapping
* pMapping
)
111 (*pMapping
->acquire
)( pMapping
);
113 (*_pMapping
->release
)( _pMapping
);
114 _pMapping
= pMapping
;
123 uno_Mapping
* pMapping
;
124 uno_freeMappingFunc freeMapping
;
125 OUString aMappingName
;
128 uno_Mapping
* pMapping_
, uno_freeMappingFunc freeMapping_
,
129 OUString aMappingName_
)
131 , pMapping( pMapping_
)
132 , freeMapping( freeMapping_
)
133 , aMappingName(std::move( aMappingName_
))
139 size_t operator()( uno_Mapping
* pKey
) const
140 { return reinterpret_cast<size_t>(pKey
); }
145 typedef std::unordered_map
<
146 OUString
, MappingEntry
* > t_OUString2Entry
;
147 typedef std::unordered_map
<
148 uno_Mapping
*, MappingEntry
*, FctPtrHash
> t_Mapping2Entry
;
154 Mutex aMappingsMutex
;
155 t_OUString2Entry aName2Entry
;
156 t_Mapping2Entry aMapping2Entry
;
158 std::mutex aCallbacksMutex
;
159 std::set
< uno_getMappingFunc
>
162 std::mutex aNegativeLibsMutex
;
163 std::set
<OUString
> aNegativeLibs
;
168 static MappingsData
& getMappingsData()
170 //TODO This memory is leaked; see #i63473# for when this should be
172 static MappingsData
* s_p(new MappingsData
);
180 * This class mediates two different mapping via uno, e.g. form any language to uno,
181 * then from uno to any other language.
183 struct uno_Mediate_Mapping
: public uno_Mapping
193 OUString aAddPurpose
;
196 Environment aFrom_
, Environment aTo_
,
197 Mapping aFrom2Uno_
, Mapping aUno2To_
,
198 OUString aAddPurpose
);
206 static void mediate_free( uno_Mapping
* pMapping
)
208 delete static_cast< uno_Mediate_Mapping
* >( pMapping
);
211 static void mediate_acquire( uno_Mapping
* pMapping
)
213 if (1 == osl_atomic_increment(
214 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
217 &pMapping
, mediate_free
,
218 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aFrom
.get(),
219 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aTo
.get(),
220 static_cast< uno_Mediate_Mapping
* >( pMapping
)->aAddPurpose
.pData
);
224 static void mediate_release( uno_Mapping
* pMapping
)
226 if (! osl_atomic_decrement(
227 & static_cast< uno_Mediate_Mapping
* >( pMapping
)->nRef
))
229 uno_revokeMapping( pMapping
);
233 static void mediate_mapInterface(
234 uno_Mapping
* pMapping
,
235 void ** ppOut
, void * pInterface
,
236 typelib_InterfaceTypeDescription
* pInterfaceTypeDescr
)
238 OSL_ENSURE( pMapping
&& ppOut
, "### null ptr!" );
239 if (!(pMapping
&& ppOut
))
242 uno_Mediate_Mapping
* that
= static_cast< uno_Mediate_Mapping
* >( pMapping
);
243 uno_Mapping
* pFrom2Uno
= that
->aFrom2Uno
.get();
245 uno_Interface
* pUnoI
= nullptr;
246 (*pFrom2Uno
->mapInterface
)( pFrom2Uno
, reinterpret_cast<void **>(&pUnoI
), pInterface
, pInterfaceTypeDescr
);
247 if (nullptr == pUnoI
)
249 void * pOut
= *ppOut
;
252 uno_ExtEnvironment
* pTo
= that
->aTo
.get()->pExtEnv
;
253 OSL_ENSURE( nullptr != pTo
, "### cannot release out interface: leaking!" );
255 (*pTo
->releaseInterface
)( pTo
, pOut
);
256 *ppOut
= nullptr; // set to 0 anyway, because mapping was not successful!
261 uno_Mapping
* pUno2To
= that
->aUno2To
.get();
262 (*pUno2To
->mapInterface
)( pUno2To
, ppOut
, pUnoI
, pInterfaceTypeDescr
);
263 (*pUnoI
->release
)( pUnoI
);
268 uno_Mediate_Mapping::uno_Mediate_Mapping(
269 Environment aFrom_
, Environment aTo_
,
270 Mapping aFrom2Uno_
, Mapping aUno2To_
,
271 OUString aAddPurpose_
)
273 , aFrom(std::move( aFrom_
))
274 , aTo(std::move( aTo_
))
275 , aFrom2Uno(std::move( aFrom2Uno_
))
276 , aUno2To(std::move( aUno2To_
))
277 , aAddPurpose(std::move( aAddPurpose_
))
279 uno_Mapping::acquire
= mediate_acquire
;
280 uno_Mapping::release
= mediate_release
;
281 uno_Mapping::mapInterface
= mediate_mapInterface
;
285 static OUString
getMappingName(
286 const Environment
& rFrom
, const Environment
& rTo
, std::u16string_view rAddPurpose
)
289 OUString::Concat(rAddPurpose
)
291 + rFrom
.getTypeName()
293 + OUString::number( reinterpret_cast< sal_IntPtr
>(rFrom
.get()), 16 )
297 + OUString::number( reinterpret_cast< sal_IntPtr
>(rTo
.get()), 16 )
301 static OUString
getBridgeName(
302 const Environment
& rFrom
, const Environment
& rTo
, std::u16string_view rAddPurpose
)
304 OUStringBuffer
aBridgeName( 16 );
305 if (!rAddPurpose
.empty())
307 aBridgeName
.append( OUString::Concat(rAddPurpose
) + "_" );
310 EnvDcp::getTypeName(rFrom
.getTypeName())
312 + EnvDcp::getTypeName(rTo
.getTypeName()) );
313 return aBridgeName
.makeStringAndClear();
316 #ifndef DISABLE_DYNLOADING
318 static void setNegativeBridge( const OUString
& rBridgeName
)
320 MappingsData
& rData
= getMappingsData();
321 std::scoped_lock
aGuard( rData
.aNegativeLibsMutex
);
322 rData
.aNegativeLibs
.insert( rBridgeName
);
327 #ifdef DISABLE_DYNLOADING
329 static uno_ext_getMappingFunc
selectMapFunc( const OUString
& rBridgeName
)
331 if (rBridgeName
.equalsAscii( CPPU_CURRENT_LANGUAGE_BINDING_NAME
"_uno" ))
332 return CPPU_ENV_uno_ext_getMapping
;
333 #if HAVE_FEATURE_JAVA
334 if (rBridgeName
.equalsAscii( "java" "_uno" ))
335 return java_uno_ext_getMapping
;
339 // I don't think the affine or log bridges will be needed on any
340 // DISABLE_DYNLOADING platform (iOS at least, possibly Android), but if
341 // somebody wants to experiment, need to find out then whether these are
343 if (rBridgeName
.equalsAscii( "affine_uno_uno" ))
344 return affine_uno_uno_ext_getMapping
;
345 if (rBridgeName
.equalsAscii( "log_uno_uno" ))
346 return log_uno_uno_ext_getMapping
;
353 static bool loadModule(osl::Module
& rModule
, const OUString
& rBridgeName
)
357 MappingsData
& rData
= getMappingsData();
358 std::scoped_lock
aGuard( rData
.aNegativeLibsMutex
);
359 const auto iFind( rData
.aNegativeLibs
.find( rBridgeName
) );
360 bNeg
= (iFind
!= rData
.aNegativeLibs
.end());
367 bModule
= cppu::detail::loadModule(rModule
, rBridgeName
);
370 // convert throw to return false
377 setNegativeBridge( rBridgeName
); // no load again
385 static Mapping
loadExternalMapping(
386 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
388 OSL_ASSERT( rFrom
.is() && rTo
.is() );
389 if (rFrom
.is() && rTo
.is())
391 #ifdef DISABLE_DYNLOADING
393 uno_ext_getMappingFunc fpGetMapFunc
= 0;
395 if (EnvDcp::getTypeName(rFrom
.getTypeName()) == UNO_LB_UNO
)
397 aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
);
398 fpGetMapFunc
= selectMapFunc( aName
);
402 aName
= getBridgeName( rFrom
, rTo
, rAddPurpose
);
403 fpGetMapFunc
= selectMapFunc( aName
);
407 aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
);
408 fpGetMapFunc
= selectMapFunc( aName
);
413 SAL_INFO("cppu", "Could not find mapfunc for " << aName
);
420 (*fpGetMapFunc
)( (uno_Mapping
**)&aExt
, rFrom
.get(), rTo
.get() );
421 OSL_ASSERT( aExt
.is() );
424 SAL_INFO("cppu", "Could not load external mapping for " << aName
);
432 if ( EnvDcp::getTypeName(rFrom
.getTypeName()) == UNO_LB_UNO
)
434 aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
);
435 bModule
= loadModule( aModule
, aName
);
439 aName
= getBridgeName( rFrom
, rTo
, rAddPurpose
);
440 bModule
= loadModule( aModule
, aName
);
444 aName
= getBridgeName( rTo
, rFrom
, rAddPurpose
);
445 bModule
= loadModule( aModule
, aName
);
450 uno_ext_getMappingFunc fpGetMapFunc
=
451 reinterpret_cast<uno_ext_getMappingFunc
>(aModule
.getSymbol( UNO_EXT_GETMAPPING
));
456 (*fpGetMapFunc
)( reinterpret_cast<uno_Mapping
**>(&aExt
), rFrom
.get(), rTo
.get() );
457 OSL_ASSERT( aExt
.is() );
465 setNegativeBridge( aName
);
473 static Mapping
getDirectMapping(
474 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
= OUString() )
477 OSL_ASSERT( rFrom
.is() && rTo
.is() );
478 if (rFrom
.is() && rTo
.is())
480 MappingsData
& rData
= getMappingsData();
481 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
483 // try to find registered mapping
484 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
485 getMappingName( rFrom
, rTo
, rAddPurpose
) ) );
487 if (iFind
== rData
.aName2Entry
.end())
490 return loadExternalMapping( rFrom
, rTo
, rAddPurpose
);
492 return Mapping( (*iFind
).second
->pMapping
);
498 static Mapping
createMediateMapping(
499 const Environment
& rFrom
, const Environment
& rTo
,
500 const Mapping
& rFrom2Uno
, const Mapping
& rUno2To
,
501 const OUString
& rAddPurpose
)
503 uno_Mapping
* pRet
= new uno_Mediate_Mapping(
504 rFrom
, rTo
, rFrom2Uno
, rUno2To
, rAddPurpose
); // ref count initially 1
506 &pRet
, mediate_free
, rFrom
.get(), rTo
.get(), rAddPurpose
.pData
);
507 Mapping
aRet( pRet
);
508 (*pRet
->release
)( pRet
);
512 static Mapping
getMediateMapping(
513 const Environment
& rFrom
, const Environment
& rTo
, const OUString
& rAddPurpose
)
518 // backwards: from dest to source of mapping chain
521 OUString
aUnoEnvTypeName( UNO_LB_UNO
);
522 if (rTo
.getTypeName() == aUnoEnvTypeName
) // to is uno
525 // no Uno2To mapping necessary
529 // get registered uno env
530 ::uno_getEnvironment( reinterpret_cast<uno_Environment
**>(&aUno
), aUnoEnvTypeName
.pData
, nullptr );
532 aUno2To
= getDirectMapping( aUno
, rTo
);
539 if (!rAddPurpose
.isEmpty()) // insert purpose mapping between new ano_uno <-> uno
541 // create anonymous uno env
543 ::uno_createEnvironment( reinterpret_cast<uno_Environment
**>(&aAnUno
), aUnoEnvTypeName
.pData
, nullptr );
545 Mapping
aAnUno2Uno( getDirectMapping( aAnUno
, aUno
, rAddPurpose
) );
546 if (! aAnUno2Uno
.is())
549 if (aUno2To
.is()) // to is not uno
551 // create another purposed mediate mapping
552 aUno2To
= createMediateMapping( aAnUno
, rTo
, aAnUno2Uno
, aUno2To
, rAddPurpose
);
553 // : ano_uno <-> uno <-> to
557 aUno2To
= aAnUno2Uno
;
558 // : ano_uno <-> to (i.e., uno)
563 Mapping
aFrom2Uno( getDirectMapping( rFrom
, aUno
) );
564 if (aFrom2Uno
.is() && aUno2To
.is())
566 return createMediateMapping( rFrom
, rTo
, aFrom2Uno
, aUno2To
, rAddPurpose
);
567 // : from <-> some uno ...
574 using namespace ::cppu
;
579 void SAL_CALL
uno_getMapping(
580 uno_Mapping
** ppMapping
, uno_Environment
* pFrom
, uno_Environment
* pTo
,
581 rtl_uString
* pAddPurpose
)
584 assert(ppMapping
!= nullptr);
585 assert(pFrom
!= nullptr);
586 assert(pTo
!= nullptr);
589 (*(*ppMapping
)->release
)( *ppMapping
);
590 *ppMapping
= nullptr;
594 Environment
aFrom( pFrom
), aTo( pTo
);
596 OUString aAddPurpose
;
598 aAddPurpose
= pAddPurpose
;
600 MappingsData
& rData
= getMappingsData();
602 // try registered mapping
604 MutexGuard
aGuard( rData
.aMappingsMutex
);
605 const t_OUString2Entry::const_iterator
iFind( rData
.aName2Entry
.find(
606 getMappingName( aFrom
, aTo
, aAddPurpose
) ) );
607 if (iFind
!= rData
.aName2Entry
.end())
608 aRet
= (*iFind
).second
->pMapping
;
611 // See if an identity mapping does fit.
612 if (!aRet
.is() && pFrom
== pTo
&& aAddPurpose
.isEmpty())
613 aRet
= createIdentityMapping(pFrom
);
617 getCascadeMapping(ppMapping
, pFrom
, pTo
, pAddPurpose
);
622 // try callback chain
624 std::unique_lock
aGuard(rData
.aCallbacksMutex
);
625 for (const auto& rCallback
: rData
.aCallbacks
)
627 (*rCallback
)(ppMapping
, pFrom
, pTo
, aAddPurpose
.pData
);
633 aRet
= loadExternalMapping( aFrom
, aTo
, aAddPurpose
); // direct try
635 aRet
= getMediateMapping( aFrom
, aTo
, aAddPurpose
); // try via uno
640 (*aRet
.get()->acquire
)( aRet
.get() );
641 *ppMapping
= aRet
.get();
645 void SAL_CALL
uno_getMappingByName(
646 uno_Mapping
** ppMapping
, rtl_uString
* pFrom
, rtl_uString
* pTo
,
647 rtl_uString
* pAddPurpose
)
650 assert(ppMapping
&& pFrom
&& pTo
&& "### null ptr!");
653 (*(*ppMapping
)->release
)( *ppMapping
);
654 *ppMapping
= nullptr;
657 uno_Environment
* pEFrom
= nullptr;
658 uno_getEnvironment( &pEFrom
, pFrom
, nullptr );
659 OSL_ENSURE( pEFrom
, "### cannot get source environment!" );
662 uno_Environment
* pETo
= nullptr;
663 uno_getEnvironment( &pETo
, pTo
, nullptr );
664 OSL_ENSURE( pETo
, "### cannot get target environment!" );
667 ::uno_getMapping( ppMapping
, pEFrom
, pETo
, pAddPurpose
);
668 (*pETo
->release
)( pETo
);
670 (*pEFrom
->release
)( pEFrom
);
675 void SAL_CALL
uno_registerMapping(
676 uno_Mapping
** ppMapping
, uno_freeMappingFunc freeMapping
,
677 uno_Environment
* pFrom
, uno_Environment
* pTo
, rtl_uString
* pAddPurpose
)
680 MappingsData
& rData
= getMappingsData();
681 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
683 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( *ppMapping
) );
684 if (iFind
== rData
.aMapping2Entry
.end())
686 OUString
aMappingName(
687 getMappingName( pFrom
, pTo
, pAddPurpose
? OUString(pAddPurpose
) : OUString() ) );
688 SAL_INFO("cppu", "> inserting new mapping: " << aMappingName
);
690 MappingEntry
* pEntry
= new MappingEntry( *ppMapping
, freeMapping
, aMappingName
);
691 rData
.aName2Entry
[ aMappingName
] = pEntry
;
692 rData
.aMapping2Entry
[ *ppMapping
] = pEntry
;
696 MappingEntry
* pEntry
= (*iFind
).second
;
699 if (pEntry
->pMapping
!= *ppMapping
) // exchange mapping to be registered
701 (*pEntry
->pMapping
->acquire
)( pEntry
->pMapping
);
702 --pEntry
->nRef
; // correct count; kill mapping to be registered
704 (*freeMapping
)( *ppMapping
);
705 *ppMapping
= pEntry
->pMapping
;
710 void SAL_CALL
uno_revokeMapping(
711 uno_Mapping
* pMapping
)
714 MappingsData
& rData
= getMappingsData();
715 ClearableMutexGuard
aGuard( rData
.aMappingsMutex
);
717 const t_Mapping2Entry::const_iterator
iFind( rData
.aMapping2Entry
.find( pMapping
) );
718 OSL_ASSERT( iFind
!= rData
.aMapping2Entry
.end() );
719 MappingEntry
* pEntry
= (*iFind
).second
;
720 if (! --pEntry
->nRef
)
722 rData
.aMapping2Entry
.erase( pEntry
->pMapping
);
723 rData
.aName2Entry
.erase( pEntry
->aMappingName
);
725 SAL_INFO("cppu", "> revoking mapping " << pEntry
->aMappingName
);
726 (*pEntry
->freeMapping
)( pEntry
->pMapping
);
732 void SAL_CALL
uno_registerMappingCallback(
733 uno_getMappingFunc pCallback
)
736 OSL_ENSURE( pCallback
, "### null ptr!" );
737 MappingsData
& rData
= getMappingsData();
738 std::unique_lock
aGuard( rData
.aCallbacksMutex
);
739 rData
.aCallbacks
.insert( pCallback
);
742 void SAL_CALL
uno_revokeMappingCallback(
743 uno_getMappingFunc pCallback
)
746 OSL_ENSURE( pCallback
, "### null ptr!" );
747 MappingsData
& rData
= getMappingsData();
748 std::unique_lock
aGuard( rData
.aCallbacksMutex
);
749 rData
.aCallbacks
.erase( pCallback
);
753 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */