1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <uno/environment.hxx>
21 #include <uno/lbnames.h>
23 #include <cppu/EnvDcp.hxx>
24 #include <cppu/Enterable.hxx>
26 #include <osl/thread.h>
27 #include <osl/thread.hxx>
28 #include <o3tl/string_view.hxx>
31 #include <unordered_map>
33 using namespace com::sun::star
;
37 struct oslThreadIdentifier_equal
39 bool operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const;
44 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const
46 bool result
= s1
== s2
;
53 struct oslThreadIdentifier_hash
55 size_t operator()(oslThreadIdentifier s1
) const;
60 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1
) const
65 typedef std::unordered_map
<oslThreadIdentifier
,
67 oslThreadIdentifier_hash
,
68 oslThreadIdentifier_equal
> ThreadMap
;
72 std::mutex s_threadMap_mutex
;
73 ThreadMap s_threadMap
;
76 static void s_setCurrent(uno_Environment
* pEnv
)
78 oslThreadIdentifier threadId
= osl::Thread::getCurrentIdentifier();
80 std::scoped_lock
guard(s_threadMap_mutex
);
83 s_threadMap
[threadId
] = pEnv
;
87 ThreadMap::iterator iEnv
= s_threadMap
.find(threadId
);
88 if( iEnv
!= s_threadMap
.end())
89 s_threadMap
.erase(iEnv
);
93 static uno_Environment
* s_getCurrent()
95 uno_Environment
* pEnv
= nullptr;
97 oslThreadIdentifier threadId
= osl::Thread::getCurrentIdentifier();
99 std::scoped_lock
guard(s_threadMap_mutex
);
100 ThreadMap::iterator iEnv
= s_threadMap
.find(threadId
);
101 if(iEnv
!= s_threadMap
.end())
108 extern "C" void SAL_CALL
uno_getCurrentEnvironment(uno_Environment
** ppEnv
, rtl_uString
* pTypeName
) noexcept
112 (*ppEnv
)->release(*ppEnv
);
116 OUString currPurpose
;
118 uno_Environment
* pCurrEnv
= s_getCurrent();
119 if (pCurrEnv
) // no environment means no purpose
120 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
122 if (pTypeName
&& rtl_uString_getLength(pTypeName
))
124 OUString envDcp
= OUString::unacquired(&pTypeName
) + currPurpose
;
126 uno_getEnvironment(ppEnv
, envDcp
.pData
, nullptr);
133 (*ppEnv
)->acquire(*ppEnv
);
137 OUString
uno_envDcp(u
"" UNO_LB_UNO
""_ustr
);
138 uno_getEnvironment(ppEnv
, uno_envDcp
.pData
, nullptr);
143 static OUString
s_getPrefix(std::u16string_view str1
, std::u16string_view str2
)
145 sal_Int32 nIndex1
= 0;
146 sal_Int32 nIndex2
= 0;
149 std::u16string_view token1
;
150 std::u16string_view token2
;
154 token1
= o3tl::getToken(str1
, 0, ':', nIndex1
);
155 token2
= o3tl::getToken(str2
, 0, ':', nIndex2
);
157 if (token1
== token2
)
158 sim
+= token1
.size() + 1;
160 while(nIndex1
== nIndex2
&& nIndex1
>= 0 && token1
== token2
);
165 result
= str1
.substr(0, sim
- 1);
170 static int s_getNextEnv(uno_Environment
** ppEnv
, uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
)
174 std::u16string_view nextPurpose
;
176 OUString currPurpose
;
178 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
180 OUString targetPurpose
;
182 targetPurpose
= cppu::EnvDcp::getPurpose(pTargetEnv
->pTypeName
);
184 OUString
intermPurpose(s_getPrefix(currPurpose
, targetPurpose
));
185 if (currPurpose
.getLength() > intermPurpose
.getLength())
187 sal_Int32 idx
= currPurpose
.lastIndexOf(':');
188 nextPurpose
= currPurpose
.subView(0, idx
);
192 else if (intermPurpose
.getLength() < targetPurpose
.getLength())
194 sal_Int32 idx
= targetPurpose
.indexOf(':', intermPurpose
.getLength() + 1);
196 nextPurpose
= targetPurpose
;
199 nextPurpose
= targetPurpose
.subView(0, idx
);
204 if (!nextPurpose
.empty())
206 OUString next_envDcp
= OUString::Concat(UNO_LB_UNO
) + nextPurpose
;
207 uno_getEnvironment(ppEnv
, next_envDcp
.pData
, nullptr);
212 (*ppEnv
)->release(*ppEnv
);
220 extern "C" { static void s_pull(va_list * pParam
)
222 uno_EnvCallee
* pCallee
= va_arg(*pParam
, uno_EnvCallee
*);
223 va_list * pXparam
= va_arg(*pParam
, va_list *);
228 static void s_callInto_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
230 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
232 pEnterable
->callInto(s_pull
, pCallee
, pParam
);
238 static void s_callInto(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
242 va_start(param
, pCallee
);
243 s_callInto_v(pEnv
, pCallee
, ¶m
);
247 static void s_callOut_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
249 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
251 pEnterable
->callOut_v(pCallee
, pParam
);
257 static void s_callOut(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
261 va_start(param
, pCallee
);
262 s_callOut_v(pEnv
, pCallee
, ¶m
);
266 static void s_environment_invoke_v(uno_Environment
*, uno_Environment
*, uno_EnvCallee
*, va_list *);
268 extern "C" { static void s_environment_invoke_vv(va_list * pParam
)
270 uno_Environment
* pCurrEnv
= va_arg(*pParam
, uno_Environment
*);
271 uno_Environment
* pTargetEnv
= va_arg(*pParam
, uno_Environment
*);
272 uno_EnvCallee
* pCallee
= va_arg(*pParam
, uno_EnvCallee
*);
273 va_list * pXparam
= va_arg(*pParam
, va_list *);
275 s_environment_invoke_v(pCurrEnv
, pTargetEnv
, pCallee
, pXparam
);
278 static void s_environment_invoke_v(uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
280 uno_Environment
* pNextEnv
= nullptr;
281 switch(s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
))
284 s_setCurrent(pNextEnv
);
285 s_callOut(pCurrEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
286 s_setCurrent(pCurrEnv
);
290 uno_Environment
* hld
= s_getCurrent();
291 s_setCurrent(pCurrEnv
);
298 s_setCurrent(pNextEnv
);
299 s_callInto(pNextEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
300 s_setCurrent(pCurrEnv
);
305 pNextEnv
->release(pNextEnv
);
308 extern "C" void SAL_CALL
uno_Environment_invoke_v(uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
) noexcept
310 s_environment_invoke_v(s_getCurrent(), pTargetEnv
, pCallee
, pParam
);
313 extern "C" void SAL_CALL
uno_Environment_invoke(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...) noexcept
317 va_start(param
, pCallee
);
318 uno_Environment_invoke_v(pEnv
, pCallee
, ¶m
);
322 extern "C" void SAL_CALL
uno_Environment_enter(uno_Environment
* pTargetEnv
) noexcept
324 uno_Environment
* pNextEnv
= nullptr;
325 uno_Environment
* pCurrEnv
= s_getCurrent();
328 while ( (res
= s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
)) != 0)
330 cppu::Enterable
* pEnterable
;
335 pEnterable
= static_cast<cppu::Enterable
*>(pCurrEnv
->pReserved
);
338 pCurrEnv
->release(pCurrEnv
);
342 pNextEnv
->acquire(pNextEnv
);
343 pEnterable
= static_cast<cppu::Enterable
*>(pNextEnv
->pReserved
);
349 s_setCurrent(pNextEnv
);
354 int SAL_CALL
uno_Environment_isValid(uno_Environment
* pEnv
, rtl_uString
** pReason
) noexcept
358 OUString
typeName(cppu::EnvDcp::getTypeName(pEnv
->pTypeName
));
359 if (typeName
== UNO_LB_UNO
)
361 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
363 result
= pEnterable
->isValid(reinterpret_cast<OUString
*>(pReason
));
367 OUString envDcp
= UNO_LB_UNO
+ cppu::EnvDcp::getPurpose(pEnv
->pTypeName
);
369 uno::Environment
env(envDcp
);
371 result
= env
.isValid(reinterpret_cast<OUString
*>(pReason
));
377 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */