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