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
)
113 (*ppEnv
)->release(*ppEnv
);
117 OUString currPurpose
;
119 uno_Environment
* pCurrEnv
= s_getCurrent();
120 if (pCurrEnv
) // no environment means no purpose
121 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
123 if (pTypeName
&& rtl_uString_getLength(pTypeName
))
125 OUString envDcp
= OUString::unacquired(&pTypeName
) + currPurpose
;
127 uno_getEnvironment(ppEnv
, envDcp
.pData
, nullptr);
134 (*ppEnv
)->acquire(*ppEnv
);
138 OUString
uno_envDcp(UNO_LB_UNO
);
139 uno_getEnvironment(ppEnv
, uno_envDcp
.pData
, nullptr);
144 static OUString
s_getPrefix(std::u16string_view str1
, std::u16string_view str2
)
146 sal_Int32 nIndex1
= 0;
147 sal_Int32 nIndex2
= 0;
150 std::u16string_view token1
;
151 std::u16string_view token2
;
155 token1
= o3tl::getToken(str1
, 0, ':', nIndex1
);
156 token2
= o3tl::getToken(str2
, 0, ':', nIndex2
);
158 if (token1
== token2
)
159 sim
+= token1
.size() + 1;
161 while(nIndex1
== nIndex2
&& nIndex1
>= 0 && token1
== token2
);
166 result
= str1
.substr(0, sim
- 1);
171 static int s_getNextEnv(uno_Environment
** ppEnv
, uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
)
175 std::u16string_view nextPurpose
;
177 OUString currPurpose
;
179 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
181 OUString targetPurpose
;
183 targetPurpose
= cppu::EnvDcp::getPurpose(pTargetEnv
->pTypeName
);
185 OUString
intermPurpose(s_getPrefix(currPurpose
, targetPurpose
));
186 if (currPurpose
.getLength() > intermPurpose
.getLength())
188 sal_Int32 idx
= currPurpose
.lastIndexOf(':');
189 nextPurpose
= currPurpose
.subView(0, idx
);
193 else if (intermPurpose
.getLength() < targetPurpose
.getLength())
195 sal_Int32 idx
= targetPurpose
.indexOf(':', intermPurpose
.getLength() + 1);
197 nextPurpose
= targetPurpose
;
200 nextPurpose
= targetPurpose
.subView(0, idx
);
205 if (!nextPurpose
.empty())
207 OUString next_envDcp
= OUString::Concat(UNO_LB_UNO
) + nextPurpose
;
208 uno_getEnvironment(ppEnv
, next_envDcp
.pData
, nullptr);
213 (*ppEnv
)->release(*ppEnv
);
221 extern "C" { static void s_pull(va_list * pParam
)
223 uno_EnvCallee
* pCallee
= va_arg(*pParam
, uno_EnvCallee
*);
224 va_list * pXparam
= va_arg(*pParam
, va_list *);
229 static void s_callInto_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
231 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
233 pEnterable
->callInto(s_pull
, pCallee
, pParam
);
239 static void s_callInto(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
243 va_start(param
, pCallee
);
244 s_callInto_v(pEnv
, pCallee
, ¶m
);
248 static void s_callOut_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
250 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
252 pEnterable
->callOut_v(pCallee
, pParam
);
258 static void s_callOut(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
262 va_start(param
, pCallee
);
263 s_callOut_v(pEnv
, pCallee
, ¶m
);
267 static void s_environment_invoke_v(uno_Environment
*, uno_Environment
*, uno_EnvCallee
*, va_list *);
269 extern "C" { static void s_environment_invoke_vv(va_list * pParam
)
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 *);
276 s_environment_invoke_v(pCurrEnv
, pTargetEnv
, pCallee
, pXparam
);
279 static void s_environment_invoke_v(uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
281 uno_Environment
* pNextEnv
= nullptr;
282 switch(s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
))
285 s_setCurrent(pNextEnv
);
286 s_callOut(pCurrEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
287 s_setCurrent(pCurrEnv
);
291 uno_Environment
* hld
= s_getCurrent();
292 s_setCurrent(pCurrEnv
);
299 s_setCurrent(pNextEnv
);
300 s_callInto(pNextEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
301 s_setCurrent(pCurrEnv
);
306 pNextEnv
->release(pNextEnv
);
309 extern "C" void SAL_CALL
uno_Environment_invoke_v(uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
312 s_environment_invoke_v(s_getCurrent(), pTargetEnv
, pCallee
, pParam
);
315 extern "C" void SAL_CALL
uno_Environment_invoke(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
320 va_start(param
, pCallee
);
321 uno_Environment_invoke_v(pEnv
, pCallee
, ¶m
);
325 extern "C" void SAL_CALL
uno_Environment_enter(uno_Environment
* pTargetEnv
)
328 uno_Environment
* pNextEnv
= nullptr;
329 uno_Environment
* pCurrEnv
= s_getCurrent();
332 while ( (res
= s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
)) != 0)
334 cppu::Enterable
* pEnterable
;
339 pEnterable
= static_cast<cppu::Enterable
*>(pCurrEnv
->pReserved
);
342 pCurrEnv
->release(pCurrEnv
);
346 pNextEnv
->acquire(pNextEnv
);
347 pEnterable
= static_cast<cppu::Enterable
*>(pNextEnv
->pReserved
);
353 s_setCurrent(pNextEnv
);
358 int SAL_CALL
uno_Environment_isValid(uno_Environment
* pEnv
, rtl_uString
** pReason
)
363 OUString
typeName(cppu::EnvDcp::getTypeName(pEnv
->pTypeName
));
364 if (typeName
== UNO_LB_UNO
)
366 cppu::Enterable
* pEnterable
= static_cast<cppu::Enterable
*>(pEnv
->pReserved
);
368 result
= pEnterable
->isValid(reinterpret_cast<OUString
*>(pReason
));
372 OUString envDcp
= UNO_LB_UNO
+ cppu::EnvDcp::getPurpose(pEnv
->pTypeName
);
374 uno::Environment
env(envDcp
);
376 result
= env
.isValid(reinterpret_cast<OUString
*>(pReason
));
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */