xref: /aoo41x/main/cppu/source/uno/lbmap.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cppu.hxx"
30 
31 #include "IdentityMapping.hxx"
32 
33 #include <hash_map>
34 #include <set>
35 #include <algorithm>
36 
37 #include "rtl/unload.h"
38 #include "rtl/ustring.hxx"
39 #include "rtl/ustrbuf.hxx"
40 #include "osl/module.h"
41 #include "osl/diagnose.h"
42 #include "osl/mutex.hxx"
43 #include "osl/interlck.h"
44 
45 #include "uno/dispatcher.h"
46 #include "uno/mapping.h"
47 #include "uno/lbnames.h"
48 #include "uno/environment.hxx"
49 
50 #include "typelib/typedescription.h"
51 
52 #include "cppu/EnvDcp.hxx"
53 #include "cascade_mapping.hxx"
54 #include "IdentityMapping.hxx"
55 #include "loadmodule.hxx"
56 
57 using namespace std;
58 using namespace osl;
59 using namespace rtl;
60 using namespace com::sun::star::uno;
61 
62 
63 namespace cppu
64 {
65 
66 class Mapping
67 {
68 	uno_Mapping * _pMapping;
69 
70 public:
71 	inline Mapping( uno_Mapping * pMapping = 0 ) SAL_THROW( () );
72 	inline Mapping( const Mapping & rMapping ) SAL_THROW( () );
73 	inline ~Mapping() SAL_THROW( () );
74 	inline Mapping & SAL_CALL operator = ( uno_Mapping * pMapping ) SAL_THROW( () );
75 	inline Mapping & SAL_CALL operator = ( const Mapping & rMapping ) SAL_THROW( () )
76 		{ return operator = ( rMapping._pMapping ); }
77 	inline uno_Mapping * SAL_CALL get() const SAL_THROW( () )
78 		{ return _pMapping; }
79 	inline sal_Bool SAL_CALL is() const SAL_THROW( () )
80 		{ return (_pMapping != 0); }
81 };
82 //__________________________________________________________________________________________________
83 inline Mapping::Mapping( uno_Mapping * pMapping ) SAL_THROW( () )
84 	: _pMapping( pMapping )
85 {
86 	if (_pMapping)
87 		(*_pMapping->acquire)( _pMapping );
88 }
89 //__________________________________________________________________________________________________
90 inline Mapping::Mapping( const Mapping & rMapping ) SAL_THROW( () )
91 	: _pMapping( rMapping._pMapping )
92 {
93 	if (_pMapping)
94 		(*_pMapping->acquire)( _pMapping );
95 }
96 //__________________________________________________________________________________________________
97 inline Mapping::~Mapping() SAL_THROW( () )
98 {
99 	if (_pMapping)
100 		(*_pMapping->release)( _pMapping );
101 }
102 //__________________________________________________________________________________________________
103 inline Mapping & Mapping::operator = ( uno_Mapping * pMapping ) SAL_THROW( () )
104 {
105 	if (pMapping)
106 		(*pMapping->acquire)( pMapping );
107 	if (_pMapping)
108 		(*_pMapping->release)( _pMapping );
109 	_pMapping = pMapping;
110 	return *this;
111 }
112 
113 //==================================================================================================
114 struct MappingEntry
115 {
116 	sal_Int32			nRef;
117 	uno_Mapping *		pMapping;
118 	uno_freeMappingFunc	freeMapping;
119 	OUString			aMappingName;
120 
121 	MappingEntry(
122 		uno_Mapping * pMapping_, uno_freeMappingFunc freeMapping_,
123 		const OUString & rMappingName_ )
124 		SAL_THROW( () )
125 		: nRef( 1 )
126 		, pMapping( pMapping_ )
127 		, freeMapping( freeMapping_ )
128 		, aMappingName( rMappingName_ )
129 		{}
130 };
131 //--------------------------------------------------------------------------------------------------
132 struct FctOUStringHash : public unary_function< const OUString &, size_t >
133 {
134 	size_t operator()( const OUString & rKey ) const SAL_THROW( () )
135 		{ return (size_t)rKey.hashCode(); }
136 };
137 //--------------------------------------------------------------------------------------------------
138 struct FctPtrHash : public unary_function< uno_Mapping *, size_t >
139 {
140 	size_t operator()( uno_Mapping * pKey ) const SAL_THROW( () )
141 		{ return (size_t)pKey; }
142 };
143 
144 typedef hash_map<
145     OUString, MappingEntry *, FctOUStringHash, equal_to< OUString > > t_OUString2Entry;
146 typedef hash_map<
147     uno_Mapping *, MappingEntry *, FctPtrHash, equal_to< uno_Mapping * > > t_Mapping2Entry;
148 
149 typedef set< uno_getMappingFunc > t_CallbackSet;
150 typedef set< OUString > t_OUStringSet;
151 
152 //==================================================================================================
153 struct MappingsData
154 {
155 	Mutex				aMappingsMutex;
156 	t_OUString2Entry	aName2Entry;
157 	t_Mapping2Entry		aMapping2Entry;
158 
159 	Mutex				aCallbacksMutex;
160 	t_CallbackSet		aCallbacks;
161 
162 	Mutex				aNegativeLibsMutex;
163 	t_OUStringSet		aNegativeLibs;
164 };
165 //--------------------------------------------------------------------------------------------------
166 static MappingsData & getMappingsData() SAL_THROW( () )
167 {
168 	static MappingsData * s_p = 0;
169 	if (! s_p)
170 	{
171 		MutexGuard aGuard( Mutex::getGlobalMutex() );
172 		if (! s_p)
173 		{
174 			//TODO  This memory is leaked; see #i63473# for when this should be
175             // changed again:
176 			s_p = new MappingsData;
177 		}
178 	}
179 	return *s_p;
180 }
181 
182 /**
183  * This class mediates two different mapping via uno, e.g. form any language to uno,
184  * then from uno to any other language.
185  */
186 struct uno_Mediate_Mapping : public uno_Mapping
187 {
188 	sal_Int32	nRef;
189 
190 	Environment aFrom;
191 	Environment aTo;
192 
193 	Mapping		aFrom2Uno;
194 	Mapping		aUno2To;
195 
196 	OUString	aAddPurpose;
197 
198 	uno_Mediate_Mapping(
199 		const Environment & rFrom_, const Environment & rTo_,
200 		const Mapping & rFrom2Uno_, const Mapping & rUno2To_,
201 		const OUString & rAddPurpose )
202 		SAL_THROW( () );
203 };
204 extern "C"
205 {
206 //--------------------------------------------------------------------------------------------------
207 static void SAL_CALL mediate_free( uno_Mapping * pMapping )
208 	SAL_THROW( () )
209 {
210 	delete static_cast< uno_Mediate_Mapping * >( pMapping );
211 }
212 //--------------------------------------------------------------------------------------------------
213 static void SAL_CALL mediate_acquire( uno_Mapping * pMapping )
214 	SAL_THROW( () )
215 {
216 	if (1 == ::osl_incrementInterlockedCount(
217 		& static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
218 	{
219 		uno_registerMapping(
220 			&pMapping, mediate_free,
221 			static_cast< uno_Mediate_Mapping * >( pMapping )->aFrom.get(),
222 			static_cast< uno_Mediate_Mapping * >( pMapping )->aTo.get(),
223 			static_cast< uno_Mediate_Mapping * >( pMapping )->aAddPurpose.pData );
224 	}
225 }
226 //--------------------------------------------------------------------------------------------------
227 static void SAL_CALL mediate_release( uno_Mapping * pMapping )
228 	SAL_THROW( () )
229 {
230 	if (! ::osl_decrementInterlockedCount(
231 		& static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
232 	{
233 		uno_revokeMapping( pMapping );
234 	}
235 }
236 //--------------------------------------------------------------------------------------------------
237 static void SAL_CALL mediate_mapInterface(
238 	uno_Mapping * pMapping,
239 	void ** ppOut, void * pInterface,
240 	typelib_InterfaceTypeDescription * pInterfaceTypeDescr )
241 	SAL_THROW( () )
242 {
243 	OSL_ENSURE( pMapping && ppOut, "### null ptr!" );
244 	if (pMapping && ppOut)
245 	{
246         uno_Mediate_Mapping * that = static_cast< uno_Mediate_Mapping * >( pMapping );
247 		uno_Mapping * pFrom2Uno = that->aFrom2Uno.get();
248 
249 		uno_Interface * pUnoI = 0;
250 		(*pFrom2Uno->mapInterface)( pFrom2Uno, (void **) &pUnoI, pInterface, pInterfaceTypeDescr );
251 		if (0 == pUnoI)
252         {
253             void * pOut = *ppOut;
254             if (0 != pOut)
255             {
256                 uno_ExtEnvironment * pTo = that->aTo.get()->pExtEnv;
257                 OSL_ENSURE( 0 != pTo, "### cannot release out interface: leaking!" );
258                 if (0 != pTo)
259                     (*pTo->releaseInterface)( pTo, pOut );
260                 *ppOut = 0; // set to 0 anyway, because mapping was not successfull!
261             }
262         }
263         else
264 		{
265             uno_Mapping * pUno2To = that->aUno2To.get();
266 			(*pUno2To->mapInterface)( pUno2To, ppOut, pUnoI, pInterfaceTypeDescr );
267 			(*pUnoI->release)( pUnoI );
268 		}
269 	}
270 }
271 }
272 //__________________________________________________________________________________________________
273 uno_Mediate_Mapping::uno_Mediate_Mapping(
274 	const Environment & rFrom_, const Environment & rTo_,
275 	const Mapping & rFrom2Uno_, const Mapping & rUno2To_,
276 	const OUString & rAddPurpose_ )
277 	SAL_THROW( () )
278 	: nRef( 1 )
279 	, aFrom( rFrom_ )
280 	, aTo( rTo_ )
281 	, aFrom2Uno( rFrom2Uno_ )
282 	, aUno2To( rUno2To_ )
283 	, aAddPurpose( rAddPurpose_ )
284 {
285 	uno_Mapping::acquire		= mediate_acquire;
286 	uno_Mapping::release		= mediate_release;
287 	uno_Mapping::mapInterface	= mediate_mapInterface;
288 }
289 
290 //==================================================================================================
291 static inline OUString getMappingName(
292 	const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
293 	SAL_THROW( () )
294 {
295 	OUStringBuffer aKey( 64 );
296 	aKey.append( rAddPurpose );
297 	aKey.append( (sal_Unicode)';' );
298 	aKey.append( rFrom.getTypeName() );
299 	aKey.append( (sal_Unicode)'[' );
300 	aKey.append( reinterpret_cast< sal_IntPtr >(rFrom.get()), 16 );
301 	aKey.appendAscii( RTL_CONSTASCII_STRINGPARAM("];") );
302 	aKey.append( rTo.getTypeName() );
303 	aKey.append( (sal_Unicode)'[' );
304 	aKey.append( reinterpret_cast< sal_IntPtr >(rTo.get()), 16 );
305 	aKey.append( (sal_Unicode)']' );
306 	return aKey.makeStringAndClear();
307 }
308 //==================================================================================================
309 static inline OUString getBridgeName(
310 	const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
311 	SAL_THROW( () )
312 {
313 	OUStringBuffer aBridgeName( 16 );
314 	if (rAddPurpose.getLength())
315 	{
316 		aBridgeName.append( rAddPurpose );
317 		aBridgeName.append( (sal_Unicode)'_' );
318 	}
319 	aBridgeName.append( EnvDcp::getTypeName(rFrom.getTypeName()) );
320 	aBridgeName.append( (sal_Unicode)'_' );
321 	aBridgeName.append( EnvDcp::getTypeName(rTo.getTypeName()) );
322 	return aBridgeName.makeStringAndClear();
323 }
324 //==================================================================================================
325 static inline void setNegativeBridge( const OUString & rBridgeName )
326 	SAL_THROW( () )
327 {
328 	MappingsData & rData = getMappingsData();
329 	MutexGuard aGuard( rData.aNegativeLibsMutex );
330 	rData.aNegativeLibs.insert( rBridgeName );
331 }
332 //==================================================================================================
333 static inline oslModule loadModule( const OUString & rBridgeName )
334 	SAL_THROW( () )
335 {
336 	sal_Bool bNeg;
337 	{
338 	MappingsData & rData = getMappingsData();
339 	MutexGuard aGuard( rData.aNegativeLibsMutex );
340 	const t_OUStringSet::const_iterator iFind( rData.aNegativeLibs.find( rBridgeName ) );
341 	bNeg = (iFind != rData.aNegativeLibs.end());
342 	}
343 
344 	if (! bNeg)
345 	{
346 		oslModule hModule = cppu::detail::loadModule( rBridgeName );
347 
348 		if (hModule)
349 			return hModule;
350 
351 		setNegativeBridge( rBridgeName ); // no load again
352 	}
353 	return 0;
354 }
355 //==================================================================================================
356 static Mapping loadExternalMapping(
357 	const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
358 	SAL_THROW( () )
359 {
360 	OSL_ASSERT( rFrom.is() && rTo.is() );
361 	if (rFrom.is() && rTo.is())
362 	{
363 		// find proper lib
364 		oslModule hModule = 0;
365 		OUString aName;
366 
367 		if (EnvDcp::getTypeName(rFrom.getTypeName()).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_LB_UNO) ))
368 			hModule = loadModule( aName = getBridgeName( rTo, rFrom, rAddPurpose ) );
369 		if (! hModule)
370 			hModule = loadModule( aName = getBridgeName( rFrom, rTo, rAddPurpose ) );
371 		if (! hModule)
372 			hModule = loadModule( aName = getBridgeName( rTo, rFrom, rAddPurpose ) );
373 
374 		if (hModule)
375 		{
376 			OUString aSymbolName( RTL_CONSTASCII_USTRINGPARAM(UNO_EXT_GETMAPPING) );
377 			uno_ext_getMappingFunc fpGetMapFunc =
378 				(uno_ext_getMappingFunc)::osl_getFunctionSymbol(
379                     hModule, aSymbolName.pData );
380 
381 			if (fpGetMapFunc)
382 			{
383 				Mapping aExt;
384 				(*fpGetMapFunc)( (uno_Mapping **)&aExt, rFrom.get(), rTo.get() );
385 				OSL_ASSERT( aExt.is() );
386 				if (aExt.is())
387                 {
388                     ::rtl_registerModuleForUnloading( hModule );
389 					return aExt;
390                 }
391 			}
392 			::osl_unloadModule( hModule );
393 			setNegativeBridge( aName );
394 		}
395 	}
396 	return Mapping();
397 }
398 
399 //==================================================================================================
400 static Mapping getDirectMapping(
401 	const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose = OUString() )
402 	SAL_THROW( () )
403 {
404 	OSL_ASSERT( rFrom.is() && rTo.is() );
405 	if (rFrom.is() && rTo.is())
406 	{
407 		MappingsData & rData = getMappingsData();
408 		ClearableMutexGuard aGuard( rData.aMappingsMutex );
409 
410 		// try to find registered mapping
411 		const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
412 			getMappingName( rFrom, rTo, rAddPurpose ) ) );
413 
414 		if (iFind == rData.aName2Entry.end())
415 		{
416 			aGuard.clear();
417 			return loadExternalMapping( rFrom, rTo, rAddPurpose );
418 		}
419 		else
420 		{
421 			return Mapping( (*iFind).second->pMapping );
422 		}
423 	}
424 	return Mapping();
425 }
426 
427 //--------------------------------------------------------------------------------------------------
428 static inline Mapping createMediateMapping(
429 	const Environment & rFrom, const Environment & rTo,
430 	const Mapping & rFrom2Uno, const Mapping & rUno2To,
431 	const OUString & rAddPurpose )
432 	SAL_THROW( () )
433 {
434 	uno_Mapping * pRet = new uno_Mediate_Mapping(
435 		rFrom, rTo, rFrom2Uno, rUno2To, rAddPurpose ); // ref count initially 1
436 	uno_registerMapping(
437 		&pRet, mediate_free, rFrom.get(), rTo.get(), rAddPurpose.pData );
438 	Mapping aRet( pRet );
439 	(*pRet->release)( pRet );
440 	return aRet;
441 }
442 //==================================================================================================
443 static Mapping getMediateMapping(
444 	const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
445 	SAL_THROW( () )
446 {
447 	Environment aUno;
448 	Mapping aUno2To;
449 
450 	// backwards: from dest to source of mapping chain
451 
452 	// connect to uno
453 	OUString aUnoEnvTypeName( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO) );
454 	if (rTo.getTypeName() == aUnoEnvTypeName) // to is uno
455 	{
456 		aUno = rTo;
457 		// no Uno2To mapping necessary
458 	}
459 	else
460 	{
461 		// get registered uno env
462 		::uno_getEnvironment( (uno_Environment **)&aUno, aUnoEnvTypeName.pData, 0 );
463 
464 		aUno2To = getDirectMapping( aUno, rTo );
465 		// : uno <-> to
466 		if (! aUno2To.is())
467 			return Mapping();
468 	}
469 
470 	// connect to uno
471 	if (rAddPurpose.getLength()) // insert purpose mapping between new ano_uno <-> uno
472 	{
473 		// create anonymous uno env
474 		Environment aAnUno;
475 		::uno_createEnvironment( (uno_Environment **)&aAnUno, aUnoEnvTypeName.pData, 0 );
476 
477 		Mapping aAnUno2Uno( getDirectMapping( aAnUno, aUno, rAddPurpose ) );
478 		if (! aAnUno2Uno.is())
479 			return Mapping();
480 
481 		if (aUno2To.is()) // to is not uno
482 		{
483 			// create another purposed mediate mapping
484 			aUno2To = createMediateMapping( aAnUno, rTo, aAnUno2Uno, aUno2To, rAddPurpose );
485 			// : ano_uno <-> uno <-> to
486 		}
487 		else
488 		{
489 			aUno2To = aAnUno2Uno;
490 			// : ano_uno <-> to (i.e., uno)
491 		}
492 		aUno = aAnUno;
493 	}
494 
495 	Mapping aFrom2Uno( getDirectMapping( rFrom, aUno ) );
496 	if (aFrom2Uno.is() && aUno2To.is())
497 	{
498 		return createMediateMapping( rFrom, rTo, aFrom2Uno, aUno2To, rAddPurpose );
499 		// : from <-> some uno ...
500 	}
501 
502 	return Mapping();
503 }
504 }
505 
506 using namespace ::cppu;
507 
508 extern "C"
509 {
510 //##################################################################################################
511 void SAL_CALL uno_getMapping(
512 	uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo,
513 	rtl_uString * pAddPurpose )
514 	SAL_THROW_EXTERN_C()
515 {
516 	OSL_ENSURE( ppMapping && pFrom && pTo, "### null ptr!" );
517 	if (*ppMapping)
518 	{
519 		(*(*ppMapping)->release)( *ppMapping );
520 		*ppMapping = 0;
521 	}
522 
523 	Mapping aRet;
524 	Environment aFrom( pFrom ), aTo( pTo );
525 
526 	OUString aAddPurpose;
527 	if (pAddPurpose)
528 		aAddPurpose = pAddPurpose;
529 
530 	MappingsData & rData = getMappingsData();
531 
532 	// try registered mapping
533 	{
534 	MutexGuard aGuard( rData.aMappingsMutex );
535 	const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
536 		getMappingName( aFrom, aTo, aAddPurpose ) ) );
537 	if (iFind != rData.aName2Entry.end())
538 		aRet = (*iFind).second->pMapping;
539 	}
540 
541 	// See if an identity mapping does fit.
542 	if (!aRet.is() && pFrom == pTo && !aAddPurpose.getLength())
543 		aRet = createIdentityMapping(pFrom);
544 
545 	if (!aRet.is())
546 	{
547 		getCascadeMapping(ppMapping, pFrom, pTo, pAddPurpose);
548 
549 		if (*ppMapping)
550 			return;
551 	}
552 
553 	if (! aRet.is()) // try callback chain
554 	{
555 		MutexGuard aGuard( rData.aCallbacksMutex );
556 		for ( t_CallbackSet::const_iterator iPos( rData.aCallbacks.begin() );
557 			  iPos != rData.aCallbacks.end(); ++iPos )
558 		{
559 			(**iPos)( ppMapping, pFrom, pTo, aAddPurpose.pData );
560 			if (*ppMapping)
561 				return;
562 		}
563 	}
564 
565 	if (! aRet.is())
566 	{
567 		aRet = loadExternalMapping( aFrom, aTo, aAddPurpose ); // direct try
568 		if (! aRet.is())
569 			aRet = getMediateMapping( aFrom, aTo, aAddPurpose ); // try via uno
570 	}
571 
572 	if (aRet.is())
573 	{
574 		(*aRet.get()->acquire)( aRet.get() );
575 		*ppMapping = aRet.get();
576 	}
577 }
578 //##################################################################################################
579 void SAL_CALL uno_getMappingByName(
580 	uno_Mapping ** ppMapping, rtl_uString * pFrom, rtl_uString * pTo,
581 	rtl_uString * pAddPurpose )
582 	SAL_THROW_EXTERN_C()
583 {
584 	OSL_ENSURE( ppMapping && pFrom && pTo, "### null ptr!" );
585 	if (*ppMapping)
586 	{
587 		(*(*ppMapping)->release)( *ppMapping );
588 		*ppMapping = 0;
589 	}
590 
591 	uno_Environment * pEFrom = 0;
592 	uno_getEnvironment( &pEFrom, pFrom, 0 );
593 	OSL_ENSURE( pEFrom, "### cannot get source environment!" );
594 	if (pEFrom)
595 	{
596 		uno_Environment * pETo = 0;
597 		uno_getEnvironment( &pETo, pTo, 0 );
598 		OSL_ENSURE( pETo, "### cannot get target environment!" );
599 		if (pETo)
600 		{
601 			::uno_getMapping( ppMapping, pEFrom, pETo, pAddPurpose );
602 			(*pETo->release)( pETo );
603 		}
604 		(*pEFrom->release)( pEFrom );
605 	}
606 }
607 
608 //##################################################################################################
609 void SAL_CALL uno_registerMapping(
610 	uno_Mapping ** ppMapping, uno_freeMappingFunc freeMapping,
611 	uno_Environment * pFrom, uno_Environment * pTo, rtl_uString * pAddPurpose )
612 	SAL_THROW_EXTERN_C()
613 {
614 	MappingsData & rData = getMappingsData();
615 	ClearableMutexGuard aGuard( rData.aMappingsMutex );
616 
617 	const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( *ppMapping ) );
618 	if (iFind == rData.aMapping2Entry.end())
619 	{
620 		OUString aMappingName(
621 			getMappingName( pFrom, pTo, pAddPurpose ? OUString(pAddPurpose) : OUString() ) );
622 #if OSL_DEBUG_LEVEL > 1
623 		OString cstr( OUStringToOString( aMappingName, RTL_TEXTENCODING_ASCII_US ) );
624 		OSL_TRACE( "> inserting new mapping: %s", cstr.getStr() );
625 #endif
626 		// count initially 1
627 		MappingEntry * pEntry = new MappingEntry( *ppMapping, freeMapping, aMappingName );
628 		rData.aName2Entry[ aMappingName ] = pEntry;
629 		rData.aMapping2Entry[ *ppMapping ] = pEntry;
630 	}
631 	else
632 	{
633 		MappingEntry * pEntry = (*iFind).second;
634 		++pEntry->nRef;
635 
636 		if (pEntry->pMapping != *ppMapping) // exchange mapping to be registered
637 		{
638 			(*pEntry->pMapping->acquire)( pEntry->pMapping );
639 			--pEntry->nRef; // correct count; kill mapping to be registered
640 			aGuard.clear();
641 			(*freeMapping)( *ppMapping );
642 			*ppMapping = pEntry->pMapping;
643 		}
644 	}
645 }
646 //##################################################################################################
647 void SAL_CALL uno_revokeMapping(
648 	uno_Mapping * pMapping )
649 	SAL_THROW_EXTERN_C()
650 {
651 	MappingsData & rData = getMappingsData();
652 	ClearableMutexGuard aGuard( rData.aMappingsMutex );
653 
654 	const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( pMapping ) );
655 	OSL_ASSERT( iFind != rData.aMapping2Entry.end() );
656 	MappingEntry * pEntry = (*iFind).second;
657 	if (! --pEntry->nRef)
658 	{
659 		rData.aMapping2Entry.erase( pEntry->pMapping );
660 		rData.aName2Entry.erase( pEntry->aMappingName );
661 		aGuard.clear();
662 #if OSL_DEBUG_LEVEL > 1
663 		OString cstr( OUStringToOString( pEntry->aMappingName, RTL_TEXTENCODING_ASCII_US  ) );
664 		OSL_TRACE( "> revoking mapping %s", cstr.getStr() );
665 #endif
666 		(*pEntry->freeMapping)( pEntry->pMapping );
667 		delete pEntry;
668 	}
669 }
670 
671 //##################################################################################################
672 void SAL_CALL uno_registerMappingCallback(
673 	uno_getMappingFunc pCallback )
674 	SAL_THROW_EXTERN_C()
675 {
676 	OSL_ENSURE( pCallback, "### null ptr!" );
677 	MappingsData & rData = getMappingsData();
678 	MutexGuard aGuard( rData.aCallbacksMutex );
679 	rData.aCallbacks.insert( pCallback );
680 }
681 //##################################################################################################
682 void SAL_CALL uno_revokeMappingCallback(
683 	uno_getMappingFunc pCallback )
684 	SAL_THROW_EXTERN_C()
685 {
686 	OSL_ENSURE( pCallback, "### null ptr!" );
687 	MappingsData & rData = getMappingsData();
688 	MutexGuard aGuard( rData.aCallbacksMutex );
689 	rData.aCallbacks.erase( pCallback );
690 }
691 } // extern "C"
692 
693