Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / cppu / source / uno / lbmap.cxx
blobcbf613784ee449cf81742b4545b8fa66006d42c7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #endif
24 #include "IdentityMapping.hxx"
26 #include <cassert>
27 #include <mutex>
28 #include <set>
29 #include <unordered_map>
30 #include <utility>
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"
51 using namespace osl;
52 using namespace com::sun::star::uno;
54 namespace cppu
57 namespace {
59 class Mapping
61 uno_Mapping * _pMapping;
63 public:
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; }
68 inline ~Mapping();
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;
78 return *this;
80 uno_Mapping * get() const
81 { return _pMapping; }
82 bool is() const
83 { return (_pMapping != nullptr); }
88 inline Mapping::Mapping( uno_Mapping * pMapping )
89 : _pMapping( pMapping )
91 if (_pMapping)
92 (*_pMapping->acquire)( _pMapping );
95 inline Mapping::Mapping( const Mapping & rMapping )
96 : _pMapping( rMapping._pMapping )
98 if (_pMapping)
99 (*_pMapping->acquire)( _pMapping );
102 inline Mapping::~Mapping()
104 if (_pMapping)
105 (*_pMapping->release)( _pMapping );
108 inline Mapping & Mapping::operator = ( uno_Mapping * pMapping )
110 if (pMapping)
111 (*pMapping->acquire)( pMapping );
112 if (_pMapping)
113 (*_pMapping->release)( _pMapping );
114 _pMapping = pMapping;
115 return *this;
118 namespace {
120 struct MappingEntry
122 sal_Int32 nRef;
123 uno_Mapping * pMapping;
124 uno_freeMappingFunc freeMapping;
125 OUString aMappingName;
127 MappingEntry(
128 uno_Mapping * pMapping_, uno_freeMappingFunc freeMapping_,
129 OUString aMappingName_ )
130 : nRef( 1 )
131 , pMapping( pMapping_ )
132 , freeMapping( freeMapping_ )
133 , aMappingName(std::move( aMappingName_ ))
137 struct FctPtrHash
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;
150 namespace {
152 struct MappingsData
154 Mutex aMappingsMutex;
155 t_OUString2Entry aName2Entry;
156 t_Mapping2Entry aMapping2Entry;
158 std::mutex aCallbacksMutex;
159 std::set< uno_getMappingFunc >
160 aCallbacks;
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
171 // changed again:
172 static MappingsData * s_p(new MappingsData);
174 return *s_p;
177 namespace {
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
185 sal_Int32 nRef;
187 Environment aFrom;
188 Environment aTo;
190 Mapping aFrom2Uno;
191 Mapping aUno2To;
193 OUString aAddPurpose;
195 uno_Mediate_Mapping(
196 Environment aFrom_, Environment aTo_,
197 Mapping aFrom2Uno_, Mapping aUno2To_,
198 OUString aAddPurpose );
203 extern "C"
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 ))
216 uno_registerMapping(
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))
240 return;
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;
250 if (nullptr != pOut)
252 uno_ExtEnvironment * pTo = that->aTo.get()->pExtEnv;
253 OSL_ENSURE( nullptr != pTo, "### cannot release out interface: leaking!" );
254 if (nullptr != pTo)
255 (*pTo->releaseInterface)( pTo, pOut );
256 *ppOut = nullptr; // set to 0 anyway, because mapping was not successful!
259 else
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_ )
272 : nRef( 1 )
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 )
288 return
289 OUString::Concat(rAddPurpose)
290 + ";"
291 + rFrom.getTypeName()
292 + "["
293 + OUString::number( reinterpret_cast< sal_IntPtr >(rFrom.get()), 16 )
294 + "];"
295 + rTo.getTypeName()
296 + "["
297 + OUString::number( reinterpret_cast< sal_IntPtr >(rTo.get()), 16 )
298 + "]";
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) + "_" );
309 aBridgeName.append(
310 EnvDcp::getTypeName(rFrom.getTypeName())
311 + "_"
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 );
325 #endif
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;
336 #endif
338 #if 0
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
342 // needed.
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;
347 #endif
348 return 0;
351 #else
353 static bool loadModule(osl::Module & rModule, const OUString & rBridgeName)
355 bool bNeg;
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());
363 if (!bNeg)
365 bool bModule;
366 try {
367 bModule = cppu::detail::loadModule(rModule, rBridgeName);
369 catch(...) {
370 // convert throw to return false
371 bModule = false;
374 if (bModule)
375 return true;
377 setNegativeBridge( rBridgeName ); // no load again
379 return false;
382 #endif
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
392 OUString aName;
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 );
400 if (! fpGetMapFunc)
402 aName = getBridgeName( rFrom, rTo, rAddPurpose );
403 fpGetMapFunc = selectMapFunc( aName );
405 if (! fpGetMapFunc)
407 aName = getBridgeName( rTo, rFrom, rAddPurpose );
408 fpGetMapFunc = selectMapFunc( aName );
411 if (! fpGetMapFunc)
413 SAL_INFO("cppu", "Could not find mapfunc for " << aName);
414 return Mapping();
417 if (fpGetMapFunc)
419 Mapping aExt;
420 (*fpGetMapFunc)( (uno_Mapping **)&aExt, rFrom.get(), rTo.get() );
421 OSL_ASSERT( aExt.is() );
422 if (aExt.is())
423 return aExt;
424 SAL_INFO("cppu", "Could not load external mapping for " << aName);
426 #else
427 // find proper lib
428 osl::Module aModule;
429 bool bModule(false);
430 OUString aName;
432 if ( EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO )
434 aName = getBridgeName( rTo, rFrom, rAddPurpose );
435 bModule = loadModule( aModule, aName );
437 if (!bModule)
439 aName = getBridgeName( rFrom, rTo, rAddPurpose );
440 bModule = loadModule( aModule, aName );
442 if (!bModule)
444 aName = getBridgeName( rTo, rFrom, rAddPurpose );
445 bModule = loadModule( aModule, aName );
448 if (bModule)
450 uno_ext_getMappingFunc fpGetMapFunc =
451 reinterpret_cast<uno_ext_getMappingFunc>(aModule.getSymbol( UNO_EXT_GETMAPPING ));
453 if (fpGetMapFunc)
455 Mapping aExt;
456 (*fpGetMapFunc)( reinterpret_cast<uno_Mapping **>(&aExt), rFrom.get(), rTo.get() );
457 OSL_ASSERT( aExt.is() );
458 if (aExt.is())
460 aModule.release();
461 return aExt;
464 aModule.unload();
465 setNegativeBridge( aName );
467 #endif
469 return Mapping();
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())
489 aGuard.clear();
490 return loadExternalMapping( rFrom, rTo, rAddPurpose );
492 return Mapping( (*iFind).second->pMapping );
494 return Mapping();
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
505 uno_registerMapping(
506 &pRet, mediate_free, rFrom.get(), rTo.get(), rAddPurpose.pData );
507 Mapping aRet( pRet );
508 (*pRet->release)( pRet );
509 return aRet;
512 static Mapping getMediateMapping(
513 const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
515 Environment aUno;
516 Mapping aUno2To;
518 // backwards: from dest to source of mapping chain
520 // connect to uno
521 OUString aUnoEnvTypeName( UNO_LB_UNO );
522 if (rTo.getTypeName() == aUnoEnvTypeName) // to is uno
524 aUno = rTo;
525 // no Uno2To mapping necessary
527 else
529 // get registered uno env
530 ::uno_getEnvironment( reinterpret_cast<uno_Environment **>(&aUno), aUnoEnvTypeName.pData, nullptr );
532 aUno2To = getDirectMapping( aUno, rTo );
533 // : uno <-> to
534 if (! aUno2To.is())
535 return Mapping();
538 // connect to uno
539 if (!rAddPurpose.isEmpty()) // insert purpose mapping between new ano_uno <-> uno
541 // create anonymous uno env
542 Environment aAnUno;
543 ::uno_createEnvironment( reinterpret_cast<uno_Environment **>(&aAnUno), aUnoEnvTypeName.pData, nullptr );
545 Mapping aAnUno2Uno( getDirectMapping( aAnUno, aUno, rAddPurpose ) );
546 if (! aAnUno2Uno.is())
547 return Mapping();
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
555 else
557 aUno2To = aAnUno2Uno;
558 // : ano_uno <-> to (i.e., uno)
560 aUno = aAnUno;
563 Mapping aFrom2Uno( getDirectMapping( rFrom, aUno ) );
564 if (aFrom2Uno.is() && aUno2To.is())
566 return createMediateMapping( rFrom, rTo, aFrom2Uno, aUno2To, rAddPurpose );
567 // : from <-> some uno ...
570 return Mapping();
574 using namespace ::cppu;
576 extern "C"
579 void SAL_CALL uno_getMapping(
580 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo,
581 rtl_uString * pAddPurpose )
582 SAL_THROW_EXTERN_C()
584 assert(ppMapping != nullptr);
585 assert(pFrom != nullptr);
586 assert(pTo != nullptr);
587 if (*ppMapping)
589 (*(*ppMapping)->release)( *ppMapping );
590 *ppMapping = nullptr;
593 Mapping aRet;
594 Environment aFrom( pFrom ), aTo( pTo );
596 OUString aAddPurpose;
597 if (pAddPurpose)
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);
615 if (!aRet.is())
617 getCascadeMapping(ppMapping, pFrom, pTo, pAddPurpose);
619 if (*ppMapping)
620 return;
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);
628 if (*ppMapping)
629 return;
633 aRet = loadExternalMapping( aFrom, aTo, aAddPurpose ); // direct try
634 if (! aRet.is())
635 aRet = getMediateMapping( aFrom, aTo, aAddPurpose ); // try via uno
638 if (aRet.is())
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 )
648 SAL_THROW_EXTERN_C()
650 assert(ppMapping && pFrom && pTo && "### null ptr!");
651 if (*ppMapping)
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!" );
660 if (pEFrom)
662 uno_Environment * pETo = nullptr;
663 uno_getEnvironment( &pETo, pTo, nullptr );
664 OSL_ENSURE( pETo, "### cannot get target environment!" );
665 if (pETo)
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 )
678 SAL_THROW_EXTERN_C()
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);
689 // count initially 1
690 MappingEntry * pEntry = new MappingEntry( *ppMapping, freeMapping, aMappingName );
691 rData.aName2Entry[ aMappingName ] = pEntry;
692 rData.aMapping2Entry[ *ppMapping ] = pEntry;
694 else
696 MappingEntry * pEntry = (*iFind).second;
697 ++pEntry->nRef;
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
703 aGuard.clear();
704 (*freeMapping)( *ppMapping );
705 *ppMapping = pEntry->pMapping;
710 void SAL_CALL uno_revokeMapping(
711 uno_Mapping * pMapping )
712 SAL_THROW_EXTERN_C()
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 );
724 aGuard.clear();
725 SAL_INFO("cppu", "> revoking mapping " << pEntry->aMappingName);
726 (*pEntry->freeMapping)( pEntry->pMapping );
727 delete pEntry;
732 void SAL_CALL uno_registerMappingCallback(
733 uno_getMappingFunc pCallback )
734 SAL_THROW_EXTERN_C()
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 )
744 SAL_THROW_EXTERN_C()
746 OSL_ENSURE( pCallback, "### null ptr!" );
747 MappingsData & rData = getMappingsData();
748 std::unique_lock aGuard( rData.aCallbacksMutex );
749 rData.aCallbacks.erase( pCallback );
751 } // extern "C"
753 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */