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