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 "rtl/instance.hxx"
28 #include "osl/thread.h"
29 #include "osl/thread.hxx"
30 #include "osl/mutex.hxx"
32 #include <unordered_map>
34 using namespace com::sun::star
;
37 struct oslThreadIdentifier_equal
39 bool operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const;
42 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const
44 bool result
= s1
== s2
;
50 struct oslThreadIdentifier_hash
52 size_t operator()(oslThreadIdentifier s1
) const;
55 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1
) const
60 typedef std::unordered_map
<oslThreadIdentifier
,
62 oslThreadIdentifier_hash
,
63 oslThreadIdentifier_equal
> ThreadMap
;
67 struct s_threadMap_mutex
: public rtl::Static
< osl::Mutex
, s_threadMap_mutex
> {};
68 struct s_threadMap
: public rtl::Static
< ThreadMap
, s_threadMap
> {};
71 static void s_setCurrent(uno_Environment
* pEnv
)
73 oslThreadIdentifier threadId
= osl::Thread::getCurrentIdentifier();
75 osl::MutexGuard
guard(s_threadMap_mutex::get());
76 ThreadMap
&rThreadMap
= s_threadMap::get();
79 rThreadMap
[threadId
] = pEnv
;
83 ThreadMap::iterator iEnv
= rThreadMap
.find(threadId
);
84 if( iEnv
!= rThreadMap
.end())
85 rThreadMap
.erase(iEnv
);
89 static uno_Environment
* s_getCurrent()
91 uno_Environment
* pEnv
= NULL
;
93 oslThreadIdentifier threadId
= osl::Thread::getCurrentIdentifier();
95 osl::MutexGuard
guard(s_threadMap_mutex::get());
96 ThreadMap
&rThreadMap
= s_threadMap::get();
97 ThreadMap::iterator iEnv
= rThreadMap
.find(threadId
);
98 if(iEnv
!= rThreadMap
.end())
105 extern "C" void SAL_CALL
uno_getCurrentEnvironment(uno_Environment
** ppEnv
, rtl_uString
* pTypeName
)
110 (*ppEnv
)->release(*ppEnv
);
114 rtl::OUString currPurpose
;
116 uno_Environment
* pCurrEnv
= s_getCurrent();
117 if (pCurrEnv
) // no environment means no purpose
118 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
120 if (pTypeName
&& rtl_uString_getLength(pTypeName
))
122 rtl::OUString
envDcp(pTypeName
);
123 envDcp
+= currPurpose
;
125 uno_getEnvironment(ppEnv
, envDcp
.pData
, NULL
);
132 (*ppEnv
)->acquire(*ppEnv
);
136 rtl::OUString
uno_envDcp(UNO_LB_UNO
);
137 uno_getEnvironment(ppEnv
, uno_envDcp
.pData
, NULL
);
142 static rtl::OUString
s_getPrefix(rtl::OUString
const & str1
, rtl::OUString
const & str2
)
144 sal_Int32 nIndex1
= 0;
145 sal_Int32 nIndex2
= 0;
148 rtl::OUString token1
;
149 rtl::OUString token2
;
153 token1
= str1
.getToken(0, ':', nIndex1
);
154 token2
= str2
.getToken(0, ':', nIndex2
);
156 if (token1
.equals(token2
))
157 sim
+= token1
.getLength() + 1;
159 while(nIndex1
== nIndex2
&& nIndex1
>= 0 && token1
.equals(token2
));
161 rtl::OUString result
;
164 result
= str1
.copy(0, sim
- 1);
169 static int s_getNextEnv(uno_Environment
** ppEnv
, uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
)
173 rtl::OUString nextPurpose
;
175 rtl::OUString currPurpose
;
177 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
179 rtl::OUString targetPurpose
;
181 targetPurpose
= cppu::EnvDcp::getPurpose(pTargetEnv
->pTypeName
);
183 rtl::OUString
intermPurpose(s_getPrefix(currPurpose
, targetPurpose
));
184 if (currPurpose
.getLength() > intermPurpose
.getLength())
186 sal_Int32 idx
= currPurpose
.lastIndexOf(':');
187 nextPurpose
= currPurpose
.copy(0, idx
);
191 else if (intermPurpose
.getLength() < targetPurpose
.getLength())
193 sal_Int32 idx
= targetPurpose
.indexOf(':', intermPurpose
.getLength() + 1);
195 nextPurpose
= targetPurpose
;
198 nextPurpose
= targetPurpose
.copy(0, idx
);
203 if (!nextPurpose
.isEmpty())
205 rtl::OUString
next_envDcp(UNO_LB_UNO
);
206 next_envDcp
+= nextPurpose
;
208 uno_getEnvironment(ppEnv
, next_envDcp
.pData
, NULL
);
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
= NULL
;
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
= NULL
;
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 rtl::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<rtl::OUString
*>(pReason
));
372 rtl::OUString
envDcp(UNO_LB_UNO
);
373 envDcp
+= cppu::EnvDcp::getPurpose(pEnv
->pTypeName
);
375 uno::Environment
env(envDcp
);
377 result
= env
.isValid(reinterpret_cast<rtl::OUString
*>(pReason
));
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */