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