Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/cppu/source/uno/EnvStack.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
#include <uno/environment.hxx>
21
#include <uno/lbnames.h>
22
23
#include <cppu/EnvDcp.hxx>
24
#include <cppu/Enterable.hxx>
25
26
#include <osl/thread.h>
27
#include <osl/thread.hxx>
28
#include <o3tl/string_view.hxx>
29
30
#include <mutex>
31
#include <unordered_map>
32
33
using namespace com::sun::star;
34
35
namespace {
36
37
struct oslThreadIdentifier_equal
38
{
39
    bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
40
};
41
42
}
43
44
bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
45
0
{
46
0
    bool result = s1 == s2;
47
48
0
    return result;
49
0
}
50
51
namespace {
52
53
struct oslThreadIdentifier_hash
54
{
55
    size_t operator()(oslThreadIdentifier s1) const;
56
};
57
58
}
59
60
size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
61
2.37M
{
62
2.37M
    return s1;
63
2.37M
}
64
65
typedef std::unordered_map<oslThreadIdentifier,
66
                        uno_Environment *,
67
                        oslThreadIdentifier_hash,
68
                        oslThreadIdentifier_equal>  ThreadMap;
69
70
namespace
71
{
72
    std::mutex s_threadMap_mutex;
73
    ThreadMap s_threadMap;
74
}
75
76
static void s_setCurrent(uno_Environment * pEnv)
77
1.11M
{
78
1.11M
    oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
79
80
1.11M
    std::scoped_lock guard(s_threadMap_mutex);
81
1.11M
    if (pEnv)
82
0
    {
83
0
        s_threadMap[threadId] = pEnv;
84
0
    }
85
1.11M
    else
86
1.11M
    {
87
1.11M
        ThreadMap::iterator iEnv = s_threadMap.find(threadId);
88
1.11M
        if( iEnv != s_threadMap.end())
89
0
            s_threadMap.erase(iEnv);
90
1.11M
    }
91
1.11M
}
92
93
static uno_Environment * s_getCurrent()
94
1.25M
{
95
1.25M
    uno_Environment * pEnv = nullptr;
96
97
1.25M
    oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
98
99
1.25M
    std::scoped_lock guard(s_threadMap_mutex);
100
1.25M
    ThreadMap::iterator iEnv = s_threadMap.find(threadId);
101
1.25M
    if(iEnv != s_threadMap.end())
102
0
        pEnv = iEnv->second;
103
104
1.25M
    return pEnv;
105
1.25M
}
106
107
108
extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName) noexcept
109
134k
{
110
134k
    if (*ppEnv)
111
0
    {
112
0
        (*ppEnv)->release(*ppEnv);
113
0
        *ppEnv = nullptr;
114
0
    }
115
116
134k
    OUString currPurpose;
117
118
134k
    uno_Environment * pCurrEnv = s_getCurrent();
119
134k
    if (pCurrEnv) // no environment means no purpose
120
0
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
121
122
134k
    if (pTypeName && rtl_uString_getLength(pTypeName))
123
134k
    {
124
134k
        OUString envDcp = OUString::unacquired(&pTypeName) + currPurpose;
125
126
134k
        uno_getEnvironment(ppEnv, envDcp.pData, nullptr);
127
134k
    }
128
0
    else
129
0
    {
130
0
        if (pCurrEnv)
131
0
        {
132
0
            *ppEnv = pCurrEnv;
133
0
            (*ppEnv)->acquire(*ppEnv);
134
0
        }
135
0
        else
136
0
        {
137
0
            OUString uno_envDcp(u"" UNO_LB_UNO ""_ustr);
138
0
            uno_getEnvironment(ppEnv, uno_envDcp.pData, nullptr);
139
0
        }
140
0
    }
141
134k
}
142
143
static OUString s_getPrefix(std::u16string_view str1, std::u16string_view str2)
144
559k
{
145
559k
    sal_Int32 nIndex1 = 0;
146
559k
    sal_Int32 nIndex2 = 0;
147
559k
    sal_Int32 sim = 0;
148
149
559k
    std::u16string_view token1;
150
559k
    std::u16string_view token2;
151
152
559k
    do
153
559k
    {
154
559k
        token1 = o3tl::getToken(str1, 0, ':', nIndex1);
155
559k
        token2 = o3tl::getToken(str2, 0, ':', nIndex2);
156
157
559k
        if (token1 == token2)
158
559k
            sim += token1.size() + 1;
159
559k
    }
160
559k
    while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2);
161
162
559k
    OUString result;
163
164
559k
    if (sim)
165
559k
        result = str1.substr(0, sim - 1);
166
167
559k
    return result;
168
559k
}
169
170
static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
171
559k
{
172
559k
    int res = 0;
173
174
559k
    std::u16string_view nextPurpose;
175
176
559k
    OUString currPurpose;
177
559k
    if (pCurrEnv)
178
0
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
179
180
559k
    OUString targetPurpose;
181
559k
    if (pTargetEnv)
182
559k
        targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
183
184
559k
    OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
185
559k
    if (currPurpose.getLength() > intermPurpose.getLength())
186
0
    {
187
0
        sal_Int32 idx = currPurpose.lastIndexOf(':');
188
0
        nextPurpose = currPurpose.subView(0, idx);
189
190
0
        res = -1;
191
0
    }
192
559k
    else if (intermPurpose.getLength() < targetPurpose.getLength())
193
0
    {
194
0
        sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
195
0
        if (idx == -1)
196
0
            nextPurpose = targetPurpose;
197
198
0
        else
199
0
            nextPurpose = targetPurpose.subView(0, idx);
200
201
0
        res = 1;
202
0
    }
203
204
559k
    if (!nextPurpose.empty())
205
0
    {
206
0
        OUString next_envDcp = OUString::Concat(UNO_LB_UNO) + nextPurpose;
207
0
        uno_getEnvironment(ppEnv, next_envDcp.pData, nullptr);
208
0
    }
209
559k
    else
210
559k
    {
211
559k
        if (*ppEnv)
212
0
            (*ppEnv)->release(*ppEnv);
213
214
559k
        *ppEnv = nullptr;
215
559k
    }
216
217
559k
    return res;
218
559k
}
219
220
extern "C" { static void s_pull(va_list * pParam)
221
0
{
222
0
    uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
223
0
    va_list       * pXparam = va_arg(*pParam, va_list *);
224
225
0
    pCallee(pXparam);
226
0
}}
227
228
static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
229
0
{
230
0
    cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
231
0
    if (pEnterable)
232
0
        pEnterable->callInto(s_pull, pCallee, pParam);
233
234
0
    else
235
0
        pCallee(pParam);
236
0
}
237
238
static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
239
0
{
240
0
    va_list param;
241
242
0
    va_start(param, pCallee);
243
0
    s_callInto_v(pEnv, pCallee, &param);
244
0
    va_end(param);
245
0
}
246
247
static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
248
0
{
249
0
    cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
250
0
    if (pEnterable)
251
0
        pEnterable->callOut_v(pCallee, pParam);
252
253
0
    else
254
0
        pCallee(pParam);
255
0
}
256
257
static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
258
0
{
259
0
    va_list param;
260
261
0
    va_start(param, pCallee);
262
0
    s_callOut_v(pEnv, pCallee, &param);
263
0
    va_end(param);
264
0
}
265
266
static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
267
268
extern "C" { static void s_environment_invoke_vv(va_list * pParam)
269
0
{
270
0
    uno_Environment * pCurrEnv    = va_arg(*pParam, uno_Environment *);
271
0
    uno_Environment * pTargetEnv  = va_arg(*pParam, uno_Environment *);
272
0
    uno_EnvCallee   * pCallee     = va_arg(*pParam, uno_EnvCallee *);
273
0
    va_list         * pXparam     = va_arg(*pParam, va_list *);
274
275
0
    s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
276
0
}}
277
278
static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
279
559k
{
280
559k
    uno_Environment * pNextEnv = nullptr;
281
559k
    switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
282
559k
    {
283
0
    case -1:
284
0
        s_setCurrent(pNextEnv);
285
0
        s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
286
0
        s_setCurrent(pCurrEnv);
287
0
        break;
288
289
559k
    case 0: {
290
559k
        uno_Environment * hld = s_getCurrent();
291
559k
        s_setCurrent(pCurrEnv);
292
559k
        pCallee(pParam);
293
559k
        s_setCurrent(hld);
294
559k
    }
295
559k
        break;
296
297
0
    case 1:
298
0
        s_setCurrent(pNextEnv);
299
0
        s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
300
0
        s_setCurrent(pCurrEnv);
301
0
        break;
302
559k
    }
303
304
559k
    if (pNextEnv)
305
0
        pNextEnv->release(pNextEnv);
306
559k
}
307
308
extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam) noexcept
309
559k
{
310
559k
    s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
311
559k
}
312
313
extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...) noexcept
314
559k
{
315
559k
    va_list param;
316
317
559k
    va_start(param, pCallee);
318
559k
    uno_Environment_invoke_v(pEnv, pCallee, &param);
319
559k
    va_end(param);
320
559k
}
321
322
extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv) noexcept
323
0
{
324
0
    uno_Environment * pNextEnv = nullptr;
325
0
    uno_Environment * pCurrEnv = s_getCurrent();
326
327
0
    int res;
328
0
    while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
329
0
    {
330
0
        cppu::Enterable * pEnterable;
331
332
0
        switch(res)
333
0
        {
334
0
        case -1:
335
0
            pEnterable = static_cast<cppu::Enterable *>(pCurrEnv->pReserved);
336
0
            if (pEnterable)
337
0
                pEnterable->leave();
338
0
            pCurrEnv->release(pCurrEnv);
339
0
            break;
340
341
0
        case 1:
342
0
            pNextEnv->acquire(pNextEnv);
343
0
            pEnterable = static_cast<cppu::Enterable *>(pNextEnv->pReserved);
344
0
            if (pEnterable)
345
0
                pEnterable->enter();
346
0
            break;
347
0
        }
348
349
0
        s_setCurrent(pNextEnv);
350
0
        pCurrEnv = pNextEnv;
351
0
    }
352
0
}
353
354
int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason) noexcept
355
0
{
356
0
    int result = 1;
357
358
0
    OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
359
0
    if (typeName == UNO_LB_UNO)
360
0
    {
361
0
        cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
362
0
        if (pEnterable)
363
0
            result = pEnterable->isValid(reinterpret_cast<OUString *>(pReason));
364
0
    }
365
0
    else
366
0
    {
367
0
        OUString envDcp = UNO_LB_UNO + cppu::EnvDcp::getPurpose(pEnv->pTypeName);
368
369
0
        uno::Environment env(envDcp);
370
371
0
        result = env.isValid(reinterpret_cast<OUString *>(pReason));
372
0
    }
373
374
0
    return result;
375
0
}
376
377
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */