Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/cppu/source/uno/lbmap.cxx
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
20
#ifdef DISABLE_DYNLOADING
21
#include <config_java.h>
22
#endif
23
24
#include "IdentityMapping.hxx"
25
26
#include <cassert>
27
#include <mutex>
28
#include <set>
29
#include <unordered_map>
30
#include <utility>
31
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>
39
40
#include <uno/dispatcher.h>
41
#include <uno/mapping.h>
42
#include <uno/lbnames.h>
43
#include <uno/environment.hxx>
44
45
#include <typelib/typedescription.h>
46
47
#include <cppu/EnvDcp.hxx>
48
#include "cascade_mapping.hxx"
49
#include "loadmodule.hxx"
50
51
using namespace osl;
52
using namespace com::sun::star::uno;
53
54
namespace cppu
55
{
56
57
namespace {
58
59
class Mapping
60
{
61
    uno_Mapping * _pMapping;
62
63
public:
64
    inline explicit Mapping( uno_Mapping * pMapping = nullptr );
65
    inline Mapping( const Mapping & rMapping );
66
0
    Mapping(Mapping && other) noexcept : _pMapping(other._pMapping)
67
0
    { other._pMapping = nullptr; }
68
    inline ~Mapping();
69
    inline Mapping & operator = ( uno_Mapping * pMapping );
70
    // move variant is sufficient
71
    Mapping & operator = ( const Mapping & rMapping ) = delete;
72
131k
    Mapping & operator =(Mapping && other) noexcept {
73
131k
        if (_pMapping != nullptr) {
74
0
            (*_pMapping->release)(_pMapping);
75
0
        }
76
131k
        _pMapping = other._pMapping;
77
131k
        other._pMapping = nullptr;
78
131k
        return *this;
79
131k
    }
80
    uno_Mapping * get() const
81
403k
        { return _pMapping; }
82
    bool is() const
83
666k
        { return (_pMapping != nullptr); }
84
};
85
86
}
87
88
inline Mapping::Mapping( uno_Mapping * pMapping )
89
265k
    : _pMapping( pMapping )
90
265k
{
91
265k
    if (_pMapping)
92
0
        (*_pMapping->acquire)( _pMapping );
93
265k
}
94
95
inline Mapping::Mapping( const Mapping & rMapping )
96
0
    : _pMapping( rMapping._pMapping )
97
0
{
98
0
    if (_pMapping)
99
0
        (*_pMapping->acquire)( _pMapping );
100
0
}
101
102
inline Mapping::~Mapping()
103
265k
{
104
265k
    if (_pMapping)
105
134k
        (*_pMapping->release)( _pMapping );
106
265k
}
107
108
inline Mapping & Mapping::operator = ( uno_Mapping * pMapping )
109
3.35k
{
110
3.35k
    if (pMapping)
111
3.35k
        (*pMapping->acquire)( pMapping );
112
3.35k
    if (_pMapping)
113
0
        (*_pMapping->release)( _pMapping );
114
3.35k
    _pMapping = pMapping;
115
3.35k
    return *this;
116
3.35k
}
117
118
namespace {
119
120
struct MappingEntry
121
{
122
    sal_Int32           nRef;
123
    uno_Mapping *       pMapping;
124
    uno_freeMappingFunc freeMapping;
125
    OUString            aMappingName;
126
127
    MappingEntry(
128
        uno_Mapping * pMapping_, uno_freeMappingFunc freeMapping_,
129
        OUString aMappingName_ )
130
131k
        : nRef( 1 )
131
131k
        , pMapping( pMapping_ )
132
131k
        , freeMapping( freeMapping_ )
133
131k
        , aMappingName(std::move( aMappingName_ ))
134
131k
        {}
135
};
136
137
struct FctPtrHash
138
{
139
    size_t operator()( uno_Mapping * pKey ) const
140
526k
        { return reinterpret_cast<size_t>(pKey); }
141
};
142
143
}
144
145
typedef std::unordered_map<
146
    OUString, MappingEntry * > t_OUString2Entry;
147
typedef std::unordered_map<
148
    uno_Mapping *, MappingEntry *, FctPtrHash > t_Mapping2Entry;
149
150
namespace {
151
152
struct MappingsData
153
{
154
    Mutex               aMappingsMutex;
155
    t_OUString2Entry    aName2Entry;
156
    t_Mapping2Entry     aMapping2Entry;
157
158
    std::mutex          aCallbacksMutex;
159
    std::set< uno_getMappingFunc >
160
                        aCallbacks;
161
162
    std::mutex          aNegativeLibsMutex;
163
    std::set<OUString>       aNegativeLibs;
164
};
165
166
}
167
168
static MappingsData & getMappingsData()
169
397k
{
170
    //TODO  This memory is leaked; see #i63473# for when this should be
171
    // changed again:
172
397k
    static MappingsData * s_p(new MappingsData);
173
174
397k
    return *s_p;
175
397k
}
176
177
namespace {
178
179
/**
180
 * This class mediates two different mapping via uno, e.g. form any language to uno,
181
 * then from uno to any other language.
182
 */
183
struct uno_Mediate_Mapping : public uno_Mapping
184
{
185
    sal_Int32   nRef;
186
187
    Environment aFrom;
188
    Environment aTo;
189
190
    Mapping     aFrom2Uno;
191
    Mapping     aUno2To;
192
193
    OUString    aAddPurpose;
194
195
    uno_Mediate_Mapping(
196
        Environment aFrom_, Environment aTo_,
197
        Mapping aFrom2Uno_, Mapping aUno2To_,
198
        OUString aAddPurpose );
199
};
200
201
}
202
203
extern "C"
204
{
205
206
static void mediate_free( uno_Mapping * pMapping )
207
0
{
208
0
    delete static_cast< uno_Mediate_Mapping * >( pMapping );
209
0
}
210
211
static void mediate_acquire( uno_Mapping * pMapping )
212
0
{
213
0
    if (1 == osl_atomic_increment(
214
0
        & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
215
0
    {
216
0
        uno_registerMapping(
217
0
            &pMapping, mediate_free,
218
0
            static_cast< uno_Mediate_Mapping * >( pMapping )->aFrom.get(),
219
0
            static_cast< uno_Mediate_Mapping * >( pMapping )->aTo.get(),
220
0
            static_cast< uno_Mediate_Mapping * >( pMapping )->aAddPurpose.pData );
221
0
    }
222
0
}
223
224
static void mediate_release( uno_Mapping * pMapping )
225
0
{
226
0
    if (! osl_atomic_decrement(
227
0
        & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef ))
228
0
    {
229
0
        uno_revokeMapping( pMapping );
230
0
    }
231
0
}
232
233
static void mediate_mapInterface(
234
    uno_Mapping * pMapping,
235
    void ** ppOut, void * pInterface,
236
    typelib_InterfaceTypeDescription * pInterfaceTypeDescr )
237
0
{
238
0
    OSL_ENSURE( pMapping && ppOut, "### null ptr!" );
239
0
    if (!(pMapping && ppOut))
240
0
        return;
241
242
0
    uno_Mediate_Mapping * that = static_cast< uno_Mediate_Mapping * >( pMapping );
243
0
    uno_Mapping * pFrom2Uno = that->aFrom2Uno.get();
244
245
0
    uno_Interface * pUnoI = nullptr;
246
0
    (*pFrom2Uno->mapInterface)( pFrom2Uno, reinterpret_cast<void **>(&pUnoI), pInterface, pInterfaceTypeDescr );
247
0
    if (nullptr == pUnoI)
248
0
    {
249
0
        void * pOut = *ppOut;
250
0
        if (nullptr != pOut)
251
0
        {
252
0
            uno_ExtEnvironment * pTo = that->aTo.get()->pExtEnv;
253
0
            OSL_ENSURE( nullptr != pTo, "### cannot release out interface: leaking!" );
254
0
            if (nullptr != pTo)
255
0
                (*pTo->releaseInterface)( pTo, pOut );
256
0
            *ppOut = nullptr; // set to 0 anyway, because mapping was not successful!
257
0
        }
258
0
    }
259
0
    else
260
0
    {
261
0
        uno_Mapping * pUno2To = that->aUno2To.get();
262
0
        (*pUno2To->mapInterface)( pUno2To, ppOut, pUnoI, pInterfaceTypeDescr );
263
0
        (*pUnoI->release)( pUnoI );
264
0
    }
265
0
}
266
}
267
268
uno_Mediate_Mapping::uno_Mediate_Mapping(
269
    Environment aFrom_, Environment aTo_,
270
    Mapping aFrom2Uno_, Mapping aUno2To_,
271
    OUString aAddPurpose_ )
272
0
    : nRef( 1 )
273
0
    , aFrom(std::move( aFrom_ ))
274
0
    , aTo(std::move( aTo_ ))
275
0
    , aFrom2Uno(std::move( aFrom2Uno_ ))
276
0
    , aUno2To(std::move( aUno2To_ ))
277
0
    , aAddPurpose(std::move( aAddPurpose_ ))
278
0
{
279
0
    uno_Mapping::acquire        = mediate_acquire;
280
0
    uno_Mapping::release        = mediate_release;
281
0
    uno_Mapping::mapInterface   = mediate_mapInterface;
282
0
}
283
284
285
static OUString getMappingName(
286
    const Environment & rFrom, const Environment & rTo, std::u16string_view rAddPurpose )
287
266k
{
288
266k
    return
289
266k
        OUString::Concat(rAddPurpose)
290
266k
        + ";"
291
266k
        + rFrom.getTypeName()
292
266k
        + "["
293
266k
        + OUString::number( reinterpret_cast< sal_IntPtr >(rFrom.get()), 16 )
294
266k
        + "];"
295
266k
        + rTo.getTypeName()
296
266k
        + "["
297
266k
        + OUString::number( reinterpret_cast< sal_IntPtr >(rTo.get()), 16 )
298
266k
        + "]";
299
266k
}
300
301
static OUString getBridgeName(
302
    const Environment & rFrom, const Environment & rTo, std::u16string_view rAddPurpose )
303
131k
{
304
131k
    OUStringBuffer aBridgeName( 16 );
305
131k
    if (!rAddPurpose.empty())
306
0
    {
307
0
        aBridgeName.append( OUString::Concat(rAddPurpose) + "_" );
308
0
    }
309
131k
    aBridgeName.append(
310
131k
        EnvDcp::getTypeName(rFrom.getTypeName())
311
131k
        + "_"
312
131k
        + EnvDcp::getTypeName(rTo.getTypeName()) );
313
131k
    return aBridgeName.makeStringAndClear();
314
131k
}
315
316
#ifndef DISABLE_DYNLOADING
317
318
static void setNegativeBridge( const OUString & rBridgeName )
319
{
320
    MappingsData & rData = getMappingsData();
321
    std::scoped_lock aGuard( rData.aNegativeLibsMutex );
322
    rData.aNegativeLibs.insert( rBridgeName );
323
}
324
325
#endif
326
327
#ifdef DISABLE_DYNLOADING
328
329
static uno_ext_getMappingFunc selectMapFunc( const OUString & rBridgeName )
330
131k
{
331
131k
    if (rBridgeName.equalsAscii( CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" ))
332
131k
        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
337
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
0
    return 0;
349
131k
}
350
351
#else
352
353
static bool loadModule(osl::Module & rModule, const OUString & rBridgeName)
354
{
355
    bool bNeg;
356
    {
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());
361
    }
362
363
    if (!bNeg)
364
    {
365
        bool bModule;
366
        try {
367
            bModule = cppu::detail::loadModule(rModule, rBridgeName);
368
        }
369
        catch(...) {
370
            // convert throw to return false
371
            bModule = false;
372
        }
373
374
        if (bModule)
375
            return true;
376
377
        setNegativeBridge( rBridgeName ); // no load again
378
    }
379
    return false;
380
}
381
382
#endif
383
384
385
static Mapping loadExternalMapping(
386
    const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
387
131k
{
388
131k
    OSL_ASSERT( rFrom.is() && rTo.is() );
389
131k
    if (rFrom.is() && rTo.is())
390
131k
    {
391
131k
#ifdef DISABLE_DYNLOADING
392
131k
        OUString aName;
393
131k
        uno_ext_getMappingFunc fpGetMapFunc = 0;
394
395
131k
        if (EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO)
396
65.6k
        {
397
65.6k
            aName = getBridgeName( rTo, rFrom, rAddPurpose );
398
65.6k
            fpGetMapFunc = selectMapFunc( aName );
399
65.6k
        }
400
131k
        if (! fpGetMapFunc)
401
65.6k
        {
402
65.6k
            aName = getBridgeName( rFrom, rTo, rAddPurpose );
403
65.6k
            fpGetMapFunc = selectMapFunc( aName );
404
65.6k
        }
405
131k
        if (! fpGetMapFunc)
406
0
        {
407
0
            aName = getBridgeName( rTo, rFrom, rAddPurpose );
408
0
            fpGetMapFunc = selectMapFunc( aName );
409
0
        }
410
411
131k
        if (! fpGetMapFunc)
412
0
        {
413
0
            SAL_INFO("cppu", "Could not find mapfunc for " << aName);
414
0
            return Mapping();
415
0
        }
416
417
131k
        if (fpGetMapFunc)
418
131k
        {
419
131k
            Mapping aExt;
420
131k
            (*fpGetMapFunc)( (uno_Mapping **)&aExt, rFrom.get(), rTo.get() );
421
131k
            OSL_ASSERT( aExt.is() );
422
131k
            if (aExt.is())
423
131k
                return aExt;
424
0
            SAL_INFO("cppu", "Could not load external mapping for " << aName);
425
0
        }
426
#else
427
        // find proper lib
428
        osl::Module aModule;
429
        bool bModule(false);
430
        OUString aName;
431
432
        if ( EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO )
433
        {
434
            aName = getBridgeName( rTo, rFrom, rAddPurpose );
435
            bModule = loadModule( aModule, aName );
436
        }
437
        if (!bModule)
438
        {
439
            aName = getBridgeName( rFrom, rTo, rAddPurpose );
440
            bModule = loadModule( aModule, aName );
441
        }
442
        if (!bModule)
443
        {
444
            aName = getBridgeName( rTo, rFrom, rAddPurpose );
445
            bModule = loadModule( aModule, aName );
446
        }
447
448
        if (bModule)
449
        {
450
            uno_ext_getMappingFunc fpGetMapFunc =
451
                reinterpret_cast<uno_ext_getMappingFunc>(aModule.getSymbol( u"" UNO_EXT_GETMAPPING ""_ustr ));
452
453
            if (fpGetMapFunc)
454
            {
455
                Mapping aExt;
456
                (*fpGetMapFunc)( reinterpret_cast<uno_Mapping **>(&aExt), rFrom.get(), rTo.get() );
457
                OSL_ASSERT( aExt.is() );
458
                if (aExt.is())
459
                {
460
                    aModule.release();
461
                    return aExt;
462
                }
463
            }
464
            aModule.unload();
465
            setNegativeBridge( aName );
466
        }
467
#endif
468
131k
    }
469
0
    return Mapping();
470
131k
}
471
472
473
static Mapping getDirectMapping(
474
    const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose = OUString() )
475
476
0
{
477
0
    OSL_ASSERT( rFrom.is() && rTo.is() );
478
0
    if (rFrom.is() && rTo.is())
479
0
    {
480
0
        MappingsData & rData = getMappingsData();
481
0
        ClearableMutexGuard aGuard( rData.aMappingsMutex );
482
483
        // try to find registered mapping
484
0
        const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
485
0
            getMappingName( rFrom, rTo, rAddPurpose ) ) );
486
487
0
        if (iFind == rData.aName2Entry.end())
488
0
        {
489
0
            aGuard.clear();
490
0
            return loadExternalMapping( rFrom, rTo, rAddPurpose );
491
0
        }
492
0
        return Mapping( (*iFind).second->pMapping );
493
0
    }
494
0
    return Mapping();
495
0
}
496
497
498
static Mapping createMediateMapping(
499
    const Environment & rFrom, const Environment & rTo,
500
    const Mapping & rFrom2Uno, const Mapping & rUno2To,
501
    const OUString & rAddPurpose )
502
0
{
503
0
    uno_Mapping * pRet = new uno_Mediate_Mapping(
504
0
        rFrom, rTo, rFrom2Uno, rUno2To, rAddPurpose ); // ref count initially 1
505
0
    uno_registerMapping(
506
0
        &pRet, mediate_free, rFrom.get(), rTo.get(), rAddPurpose.pData );
507
0
    Mapping aRet( pRet );
508
0
    (*pRet->release)( pRet );
509
0
    return aRet;
510
0
}
511
512
static Mapping getMediateMapping(
513
    const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose )
514
0
{
515
0
    Environment aUno;
516
0
    Mapping aUno2To;
517
518
    // backwards: from dest to source of mapping chain
519
520
    // connect to uno
521
0
    OUString aUnoEnvTypeName( u"" UNO_LB_UNO ""_ustr );
522
0
    if (rTo.getTypeName() == aUnoEnvTypeName) // to is uno
523
0
    {
524
0
        aUno = rTo;
525
        // no Uno2To mapping necessary
526
0
    }
527
0
    else
528
0
    {
529
        // get registered uno env
530
0
        ::uno_getEnvironment( reinterpret_cast<uno_Environment **>(&aUno), aUnoEnvTypeName.pData, nullptr );
531
532
0
        aUno2To = getDirectMapping( aUno, rTo );
533
        // : uno <-> to
534
0
        if (! aUno2To.is())
535
0
            return Mapping();
536
0
    }
537
538
    // connect to uno
539
0
    if (!rAddPurpose.isEmpty()) // insert purpose mapping between new ano_uno <-> uno
540
0
    {
541
        // create anonymous uno env
542
0
        Environment aAnUno;
543
0
        ::uno_createEnvironment( reinterpret_cast<uno_Environment **>(&aAnUno), aUnoEnvTypeName.pData, nullptr );
544
545
0
        Mapping aAnUno2Uno( getDirectMapping( aAnUno, aUno, rAddPurpose ) );
546
0
        if (! aAnUno2Uno.is())
547
0
            return Mapping();
548
549
0
        if (aUno2To.is()) // to is not uno
550
0
        {
551
            // create another purposed mediate mapping
552
0
            aUno2To = createMediateMapping( aAnUno, rTo, aAnUno2Uno, aUno2To, rAddPurpose );
553
            // : ano_uno <-> uno <-> to
554
0
        }
555
0
        else
556
0
        {
557
0
            aUno2To = std::move(aAnUno2Uno);
558
            // : ano_uno <-> to (i.e., uno)
559
0
        }
560
0
        aUno = std::move(aAnUno);
561
0
    }
562
563
0
    Mapping aFrom2Uno( getDirectMapping( rFrom, aUno ) );
564
0
    if (aFrom2Uno.is() && aUno2To.is())
565
0
    {
566
0
        return createMediateMapping( rFrom, rTo, aFrom2Uno, aUno2To, rAddPurpose );
567
        // : from <-> some uno ...
568
0
    }
569
570
0
    return Mapping();
571
0
}
572
}
573
574
using namespace ::cppu;
575
576
extern "C"
577
{
578
579
void SAL_CALL uno_getMapping(
580
    uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo,
581
    rtl_uString * pAddPurpose ) noexcept
582
134k
{
583
134k
    assert(ppMapping != nullptr);
584
134k
    assert(pFrom != nullptr);
585
134k
    assert(pTo != nullptr);
586
134k
    if (*ppMapping)
587
0
    {
588
0
        (*(*ppMapping)->release)( *ppMapping );
589
0
        *ppMapping = nullptr;
590
0
    }
591
592
134k
    Mapping aRet;
593
134k
    Environment aFrom( pFrom ), aTo( pTo );
594
595
134k
    OUString aAddPurpose;
596
134k
    if (pAddPurpose)
597
134k
        aAddPurpose = pAddPurpose;
598
599
134k
    MappingsData & rData = getMappingsData();
600
601
    // try registered mapping
602
134k
    {
603
134k
    MutexGuard aGuard( rData.aMappingsMutex );
604
134k
    const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find(
605
134k
        getMappingName( aFrom, aTo, aAddPurpose ) ) );
606
134k
    if (iFind != rData.aName2Entry.end())
607
3.03k
        aRet = (*iFind).second->pMapping;
608
134k
    }
609
610
    // See if an identity mapping does fit.
611
134k
    if (!aRet.is() && pFrom == pTo && aAddPurpose.isEmpty())
612
318
        aRet = createIdentityMapping(pFrom);
613
614
134k
    if (!aRet.is())
615
131k
    {
616
131k
        getCascadeMapping(ppMapping, pFrom, pTo, pAddPurpose);
617
618
131k
        if (*ppMapping)
619
0
            return;
620
621
        // try callback chain
622
131k
        {
623
131k
            std::unique_lock aGuard(rData.aCallbacksMutex);
624
131k
            for (const auto& rCallback : rData.aCallbacks)
625
0
            {
626
0
                (*rCallback)(ppMapping, pFrom, pTo, aAddPurpose.pData);
627
0
                if (*ppMapping)
628
0
                    return;
629
0
            }
630
131k
        }
631
632
131k
        aRet = loadExternalMapping( aFrom, aTo, aAddPurpose ); // direct try
633
131k
        if (! aRet.is())
634
0
            aRet = getMediateMapping( aFrom, aTo, aAddPurpose ); // try via uno
635
131k
    }
636
637
134k
    if (aRet.is())
638
134k
    {
639
134k
        (*aRet.get()->acquire)( aRet.get() );
640
134k
        *ppMapping = aRet.get();
641
134k
    }
642
134k
}
643
644
void SAL_CALL uno_getMappingByName(
645
    uno_Mapping ** ppMapping, rtl_uString * pFrom, rtl_uString * pTo,
646
    rtl_uString * pAddPurpose ) noexcept
647
4
{
648
4
    assert(ppMapping && pFrom && pTo && "### null ptr!");
649
4
    if (*ppMapping)
650
0
    {
651
0
        (*(*ppMapping)->release)( *ppMapping );
652
0
        *ppMapping = nullptr;
653
0
    }
654
655
4
    uno_Environment * pEFrom = nullptr;
656
4
    uno_getEnvironment( &pEFrom, pFrom, nullptr );
657
4
    OSL_ENSURE( pEFrom, "### cannot get source environment!" );
658
4
    if (pEFrom)
659
4
    {
660
4
        uno_Environment * pETo = nullptr;
661
4
        uno_getEnvironment( &pETo, pTo, nullptr );
662
4
        OSL_ENSURE( pETo, "### cannot get target environment!" );
663
4
        if (pETo)
664
4
        {
665
4
            ::uno_getMapping( ppMapping, pEFrom, pETo, pAddPurpose );
666
4
            (*pETo->release)( pETo );
667
4
        }
668
4
        (*pEFrom->release)( pEFrom );
669
4
    }
670
4
}
671
672
673
void SAL_CALL uno_registerMapping(
674
    uno_Mapping ** ppMapping, uno_freeMappingFunc freeMapping,
675
    uno_Environment * pFrom, uno_Environment * pTo, rtl_uString * pAddPurpose ) noexcept
676
131k
{
677
131k
    MappingsData & rData = getMappingsData();
678
131k
    ClearableMutexGuard aGuard( rData.aMappingsMutex );
679
680
131k
    const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( *ppMapping ) );
681
131k
    if (iFind == rData.aMapping2Entry.end())
682
131k
    {
683
131k
        OUString aMappingName(
684
131k
            getMappingName( pFrom, pTo, pAddPurpose ? OUString(pAddPurpose) : OUString() ) );
685
131k
        SAL_INFO("cppu", "> inserting new mapping: " << aMappingName);
686
        // count initially 1
687
131k
        MappingEntry * pEntry = new MappingEntry( *ppMapping, freeMapping, aMappingName );
688
131k
        rData.aName2Entry[ aMappingName ] = pEntry;
689
131k
        rData.aMapping2Entry[ *ppMapping ] = pEntry;
690
131k
    }
691
0
    else
692
0
    {
693
0
        MappingEntry * pEntry = (*iFind).second;
694
0
        ++pEntry->nRef;
695
696
0
        if (pEntry->pMapping != *ppMapping) // exchange mapping to be registered
697
0
        {
698
0
            (*pEntry->pMapping->acquire)( pEntry->pMapping );
699
0
            --pEntry->nRef; // correct count; kill mapping to be registered
700
0
            aGuard.clear();
701
0
            (*freeMapping)( *ppMapping );
702
0
            *ppMapping = pEntry->pMapping;
703
0
        }
704
0
    }
705
131k
}
706
707
void SAL_CALL uno_revokeMapping(
708
    uno_Mapping * pMapping ) noexcept
709
131k
{
710
131k
    MappingsData & rData = getMappingsData();
711
131k
    ClearableMutexGuard aGuard( rData.aMappingsMutex );
712
713
131k
    const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( pMapping ) );
714
131k
    assert(iFind != rData.aMapping2Entry.end() && "pMapping must be registered to be removed");
715
131k
    MappingEntry * pEntry = (*iFind).second;
716
131k
    if (! --pEntry->nRef)
717
131k
    {
718
131k
        rData.aMapping2Entry.erase( pEntry->pMapping );
719
131k
        rData.aName2Entry.erase( pEntry->aMappingName );
720
131k
        aGuard.clear();
721
131k
        SAL_INFO("cppu", "> revoking mapping " << pEntry->aMappingName);
722
131k
        (*pEntry->freeMapping)( pEntry->pMapping );
723
131k
        delete pEntry;
724
131k
    }
725
131k
}
726
727
728
void SAL_CALL uno_registerMappingCallback(
729
    uno_getMappingFunc pCallback ) noexcept
730
0
{
731
0
    OSL_ENSURE( pCallback, "### null ptr!" );
732
0
    MappingsData & rData = getMappingsData();
733
0
    std::unique_lock aGuard( rData.aCallbacksMutex );
734
0
    rData.aCallbacks.insert( pCallback );
735
0
}
736
737
void SAL_CALL uno_revokeMappingCallback(
738
    uno_getMappingFunc pCallback ) noexcept
739
0
{
740
0
    OSL_ENSURE( pCallback, "### null ptr!" );
741
0
    MappingsData & rData = getMappingsData();
742
0
    std::unique_lock aGuard( rData.aCallbacksMutex );
743
0
    rData.aCallbacks.erase( pCallback );
744
0
}
745
} // extern "C"
746
747
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */