Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/cppu/source/uno/cascade_mapping.cxx
Line
Count
Source
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
#include <osl/interlck.h>
21
#include <rtl/ustring.hxx>
22
#include <uno/environment.hxx>
23
#include <uno/lbnames.h>
24
#include <uno/mapping.hxx>
25
#include <uno/dispatcher.h>
26
#include <o3tl/string_view.hxx>
27
28
#include <cppu/EnvDcp.hxx>
29
30
#include "cascade_mapping.hxx"
31
32
using namespace com::sun::star;
33
34
namespace {
35
36
class MediatorMapping : public uno_Mapping
37
{
38
    oslInterlockedCount m_refCount;
39
40
    uno::Mapping        m_from2uno;
41
    uno::Mapping        m_uno2to;
42
43
    uno::Environment    m_from;
44
    uno::Environment    m_interm;
45
    uno::Environment    m_to;
46
47
public:
48
    void acquire();
49
    void release();
50
51
    void mapInterface(void                            ** ppOut,
52
                      void                             * pInterface,
53
                      typelib_InterfaceTypeDescription * pInterfaceTypeDescr);
54
    MediatorMapping(uno_Environment * pFrom,
55
                    uno_Environment * pInterm,
56
                    uno_Environment * pTo);
57
};
58
59
}
60
61
extern "C" {
62
static void s_acquire(uno_Mapping * mapping)
63
0
{
64
0
    MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
65
0
    pMediatorMapping->acquire();
66
0
}
67
68
static void s_release(uno_Mapping * mapping)
69
0
{
70
0
    MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping);
71
0
    pMediatorMapping->release();
72
0
}
73
74
static void s_mapInterface(
75
    uno_Mapping                      * mapping,
76
    void                            ** ppOut,
77
    void                             * pInterface,
78
    typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
79
0
{
80
0
    MediatorMapping   * pMediatorMapping  = static_cast<MediatorMapping *>(mapping);
81
0
    pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr);
82
0
}
83
}
84
85
MediatorMapping::MediatorMapping(uno_Environment * pFrom,
86
                                 uno_Environment * pInterm,
87
                                 uno_Environment * pTo)
88
0
    : m_refCount(0),
89
0
      m_from2uno(pFrom, pInterm),
90
0
      m_uno2to  (pInterm, pTo),
91
0
      m_from    (pFrom),
92
0
      m_interm  (pInterm),
93
0
      m_to      (pTo)
94
0
{
95
0
    if (!m_from2uno.get() || !m_uno2to.get())
96
0
        abort();
97
98
0
    uno_Mapping::acquire      = s_acquire;
99
0
    uno_Mapping::release      = s_release;
100
0
    uno_Mapping::mapInterface = s_mapInterface;
101
0
}
102
103
void MediatorMapping::acquire()
104
0
{
105
0
    osl_atomic_increment(&m_refCount);
106
0
}
107
108
void MediatorMapping::release()
109
0
{
110
0
    if (osl_atomic_decrement(&m_refCount) == 0)
111
0
    {
112
0
        ::uno_revokeMapping(this);
113
0
    }
114
0
}
115
116
extern "C" { static void s_mapInterface_v(va_list * pParam)
117
0
{
118
0
    void                            ** ppOut               = va_arg(*pParam, void **);
119
0
    void                             * pInterface          = va_arg(*pParam, void *);
120
0
    typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
121
0
    uno_Mapping                      * pMapping            = va_arg(*pParam, uno_Mapping *);
122
123
0
    pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr);
124
0
}}
125
126
void MediatorMapping::mapInterface(
127
    void                            ** ppOut,
128
    void                             * pInterface,
129
    typelib_InterfaceTypeDescription * pInterfaceTypeDescr)
130
0
{
131
0
    if (*ppOut != nullptr)
132
0
    {
133
0
        uno_ExtEnvironment * env = m_to.get()->pExtEnv;
134
0
        assert(env != nullptr);
135
0
        env->releaseInterface( env, *ppOut );
136
0
        *ppOut = nullptr;
137
0
    }
138
139
0
    void * ret = nullptr;
140
0
    uno_Interface * pUnoI = nullptr;
141
142
0
    m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get());
143
144
0
    m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr);
145
146
0
    if (pUnoI)
147
0
        m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI);
148
149
0
    *ppOut = ret;
150
0
}
151
152
extern "C" { static void s_MediatorMapping_free(uno_Mapping * pMapping) noexcept
153
0
{
154
0
    delete static_cast<MediatorMapping *>(pMapping);
155
0
}}
156
157
158
static OUString getPrefix(std::u16string_view str1, std::u16string_view str2)
159
0
{
160
0
    sal_Int32 nIndex1 = 0;
161
0
    sal_Int32 nIndex2 = 0;
162
0
    sal_Int32 sim = 0;
163
164
0
    std::u16string_view token1;
165
0
    std::u16string_view token2;
166
167
0
    do
168
0
    {
169
0
        token1 = o3tl::getToken(str1, 0, ':', nIndex1);
170
0
        token2 = o3tl::getToken(str2, 0, ':', nIndex2);
171
172
0
        if (token1 == token2)
173
0
            sim += token1.size() + 1;
174
0
    }
175
0
    while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2);
176
177
0
    OUString result;
178
179
0
    if (sim)
180
0
        result = str1.substr(0, sim - 1);
181
182
0
    return result;
183
0
}
184
185
//  OUString str1("abc:def:ghi");
186
//  OUString str2("abc:def");
187
//  OUString str3("abc");
188
//  OUString str4("");
189
190
//  OUString pref;
191
192
//  pref = getPrefix(str1, str1);
193
//  pref = getPrefix(str1, str2);
194
//  pref = getPrefix(str1, str3);
195
//  pref = getPrefix(str1, str4);
196
197
//  pref = getPrefix(str2, str1);
198
//  pref = getPrefix(str3, str1);
199
//  pref = getPrefix(str4, str1);
200
201
202
void getCascadeMapping(uno_Mapping     ** ppMapping,
203
                       uno_Environment  * pFrom,
204
                       uno_Environment  * pTo,
205
                       rtl_uString      * pAddPurpose)
206
136k
{
207
136k
    if (pAddPurpose && pAddPurpose->length)
208
0
        return;
209
210
136k
    OUString uno_envType(u"" UNO_LB_UNO ""_ustr);
211
212
136k
    OUString from_envType    = cppu::EnvDcp::getTypeName(pFrom->pTypeName);
213
136k
    OUString to_envType      = cppu::EnvDcp::getTypeName(pTo->pTypeName);
214
136k
    OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName);
215
136k
    OUString to_envPurpose   = cppu::EnvDcp::getPurpose(pTo->pTypeName);
216
217
#ifdef LOG_CALLING_named_purpose_getMapping
218
    OString s_from_name = OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US);
219
    OString s_to_name   = OUStringToOString(pTo->pTypeName,   RTL_TEXTENCODING_ASCII_US);
220
221
    std::cerr << __FUNCTION__ << " - creating mediation ";
222
    std::cerr << "pFrom: " << s_from_name.getStr();
223
    std::cerr <<" pTo: "   << s_to_name.getStr() << std::endl;
224
#endif
225
226
136k
    if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla
227
136k
        return;
228
229
    // reaching this point means, we need a mediated mapping!!!
230
    // we generally mediate via uno[:free]
231
0
    uno_Environment * pInterm = nullptr;
232
233
    // chained uno -> uno
234
0
    if (from_envType == uno_envType && to_envType == uno_envType)
235
0
    {
236
0
        OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
237
238
0
        OUString uno_envDcp = uno_envType + purpose;
239
240
        // direct mapping possible?
241
        // uno:bla-->uno:bla:blubb
242
0
        if (from_envPurpose == purpose)
243
0
        {
244
0
            OUString rest = to_envPurpose.copy(purpose.getLength());
245
246
0
            sal_Int32 index = rest.indexOf(':', 1);
247
0
            if (index == -1)
248
0
            {
249
0
                uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
250
0
                return;
251
0
            }
252
253
0
            uno_envDcp += rest.subView(0, index);
254
0
        }
255
0
        else if (to_envPurpose == purpose)
256
0
        {
257
0
            OUString rest = from_envPurpose.copy(purpose.getLength());
258
259
0
            sal_Int32 index = rest.indexOf(':', 1);
260
0
            if (index == -1)
261
0
            {
262
0
                uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData);
263
0
                return;
264
0
            }
265
266
0
            uno_envDcp += rest.subView(0, index);
267
0
        }
268
269
0
        uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr);
270
0
    }
271
0
    else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ?
272
        // mediate via uno:purpose(fromEnv)
273
0
    {
274
0
        OUString     envDcp = uno_envType + from_envPurpose;
275
0
        uno_getEnvironment(&pInterm, envDcp.pData, nullptr);
276
0
    }
277
0
    else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>?
278
        // mediate via uno(context)
279
0
    {
280
0
        OUString     envDcp = uno_envType + to_envPurpose;
281
0
        uno_getEnvironment(&pInterm, envDcp.pData, nullptr);
282
0
    }
283
0
    else // everything else
284
        // mediate via uno:purpose
285
0
    {
286
0
        OUString purpose = getPrefix(from_envPurpose, to_envPurpose);
287
288
0
        OUString uno_envDcp = uno_envType + purpose;
289
290
0
        uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr);
291
0
    }
292
293
0
    uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo);
294
0
    pInterm->release(pInterm);
295
296
297
0
    pMapping->acquire(pMapping);
298
299
0
    ::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose);
300
301
0
    if (*ppMapping)
302
0
        (*ppMapping)->release(*ppMapping);
303
304
0
    *ppMapping = pMapping;
305
0
}
306
307
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */