1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "uno/environment.hxx"
25
26 #include "cppu/EnvDcp.hxx"
27 #include "cppu/Enterable.hxx"
28
29 #include "osl/thread.h"
30 #include "osl/mutex.hxx"
31
32 #include <hash_map>
33
34
35 using namespace com::sun::star;
36
37
38 struct SAL_DLLPRIVATE oslThreadIdentifier_equal
39 {
40 bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
41 };
42
operator ()(oslThreadIdentifier s1,oslThreadIdentifier s2) const43 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
44 {
45 bool result = s1 == s2;
46
47 return result;
48 }
49
50
51 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
52 {
53 size_t operator()(oslThreadIdentifier s1) const;
54 };
55
operator ()(oslThreadIdentifier s1) const56 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
57 {
58 return s1;
59 }
60
61 typedef ::std::hash_map<oslThreadIdentifier,
62 uno_Environment *,
63 oslThreadIdentifier_hash,
64 oslThreadIdentifier_equal> ThreadMap;
65
66 static osl::Mutex s_threadMap_mutex;
67 static ThreadMap s_threadMap;
68
69
70 static rtl::OUString s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));
71
s_setCurrent(uno_Environment * pEnv)72 static void s_setCurrent(uno_Environment * pEnv)
73 {
74 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
75
76 osl::MutexGuard guard(s_threadMap_mutex);
77 if (pEnv)
78 s_threadMap[threadId] = pEnv;
79 else
80 {
81 ThreadMap::iterator iEnv = s_threadMap.find(threadId);
82 if( iEnv != s_threadMap.end())
83 s_threadMap.erase(iEnv);
84 }
85 }
86
s_getCurrent(void)87 static uno_Environment * s_getCurrent(void)
88 {
89 uno_Environment * pEnv = NULL;
90
91 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
92
93 osl::MutexGuard guard(s_threadMap_mutex);
94 ThreadMap::iterator iEnv = s_threadMap.find(threadId);
95 if(iEnv != s_threadMap.end())
96 pEnv = iEnv->second;
97
98 return pEnv;
99 }
100
101
uno_getCurrentEnvironment(uno_Environment ** ppEnv,rtl_uString * pTypeName)102 extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
103 SAL_THROW_EXTERN_C()
104 {
105 if (*ppEnv)
106 {
107 (*ppEnv)->release(*ppEnv);
108 *ppEnv = NULL;
109 }
110
111 rtl::OUString currPurpose;
112
113 uno_Environment * pCurrEnv = s_getCurrent();
114 if (pCurrEnv) // no environment means no purpose
115 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
116
117 if (pTypeName && rtl_uString_getLength(pTypeName))
118 {
119 rtl::OUString envDcp(pTypeName);
120 envDcp += currPurpose;
121
122 uno_getEnvironment(ppEnv, envDcp.pData, NULL);
123 }
124 else
125 {
126 if (pCurrEnv)
127 {
128 *ppEnv = pCurrEnv;
129 (*ppEnv)->acquire(*ppEnv);
130 }
131 else
132 uno_getEnvironment(ppEnv, s_uno_envDcp.pData, NULL);
133
134 }
135 }
136
s_getPrefix(rtl::OUString const & str1,rtl::OUString const & str2)137 static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
138 {
139 sal_Int32 nIndex1 = 0;
140 sal_Int32 nIndex2 = 0;
141 sal_Int32 sim = 0;
142
143 rtl::OUString token1;
144 rtl::OUString token2;
145
146 do
147 {
148 token1 = str1.getToken(0, ':', nIndex1);
149 token2 = str2.getToken(0, ':', nIndex2);
150
151 if (token1.equals(token2))
152 sim += token1.getLength() + 1;
153 }
154 while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
155
156 rtl::OUString result;
157
158 if (sim)
159 result = str1.copy(0, sim - 1);
160
161 return result;
162 }
163
s_getNextEnv(uno_Environment ** ppEnv,uno_Environment * pCurrEnv,uno_Environment * pTargetEnv)164 static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
165 {
166 int res = 0;
167
168 rtl::OUString nextPurpose;
169
170 rtl::OUString currPurpose;
171 if (pCurrEnv)
172 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
173
174 rtl::OUString targetPurpose;
175 if (pTargetEnv)
176 targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
177
178 rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
179 if (currPurpose.getLength() > intermPurpose.getLength())
180 {
181 sal_Int32 idx = currPurpose.lastIndexOf(':');
182 nextPurpose = currPurpose.copy(0, idx);
183
184 res = -1;
185 }
186 else if (intermPurpose.getLength() < targetPurpose.getLength())
187 {
188 sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
189 if (idx == -1)
190 nextPurpose = targetPurpose;
191
192 else
193 nextPurpose = targetPurpose.copy(0, idx);
194
195 res = 1;
196 }
197
198 if (nextPurpose.getLength())
199 {
200 rtl::OUString next_envDcp(s_uno_envDcp);
201 next_envDcp += nextPurpose;
202
203 uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
204 }
205 else
206 {
207 if (*ppEnv)
208 (*ppEnv)->release(*ppEnv);
209
210 *ppEnv = NULL;
211 }
212
213 return res;
214 }
215
s_pull(va_list * pParam)216 extern "C" { static void s_pull(va_list * pParam)
217 {
218 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
219 va_list * pXparam = va_arg(*pParam, va_list *);
220
221 pCallee(pXparam);
222 }}
223
s_callInto_v(uno_Environment * pEnv,uno_EnvCallee * pCallee,va_list * pParam)224 static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
225 {
226 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
227 if (pEnterable)
228 pEnterable->callInto(s_pull, pCallee, pParam);
229
230 else
231 pCallee(pParam);
232 }
233
s_callInto(uno_Environment * pEnv,uno_EnvCallee * pCallee,...)234 static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
235 {
236 va_list param;
237
238 va_start(param, pCallee);
239 s_callInto_v(pEnv, pCallee, ¶m);
240 va_end(param);
241 }
242
s_callOut_v(uno_Environment * pEnv,uno_EnvCallee * pCallee,va_list * pParam)243 static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
244 {
245 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
246 if (pEnterable)
247 pEnterable->callOut_v(pCallee, pParam);
248
249 else
250 pCallee(pParam);
251 }
252
s_callOut(uno_Environment * pEnv,uno_EnvCallee * pCallee,...)253 static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
254 {
255 va_list param;
256
257 va_start(param, pCallee);
258 s_callOut_v(pEnv, pCallee, ¶m);
259 va_end(param);
260 }
261
262 static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
263
s_environment_invoke_vv(va_list * pParam)264 extern "C" { static void s_environment_invoke_vv(va_list * pParam)
265 {
266 uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *);
267 uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *);
268 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
269 va_list * pXparam = va_arg(*pParam, va_list *);
270
271 s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
272 }}
273
s_environment_invoke_v(uno_Environment * pCurrEnv,uno_Environment * pTargetEnv,uno_EnvCallee * pCallee,va_list * pParam)274 static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
275 {
276 uno_Environment * pNextEnv = NULL;
277 switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
278 {
279 case -1:
280 s_setCurrent(pNextEnv);
281 s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
282 s_setCurrent(pCurrEnv);
283 break;
284
285 case 0: {
286 uno_Environment * hld = s_getCurrent();
287 s_setCurrent(pCurrEnv);
288 pCallee(pParam);
289 s_setCurrent(hld);
290 }
291 break;
292
293 case 1:
294 s_setCurrent(pNextEnv);
295 s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
296 s_setCurrent(pCurrEnv);
297 break;
298 }
299
300 if (pNextEnv)
301 pNextEnv->release(pNextEnv);
302 }
303
uno_Environment_invoke_v(uno_Environment * pTargetEnv,uno_EnvCallee * pCallee,va_list * pParam)304 extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
305 SAL_THROW_EXTERN_C()
306 {
307 s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
308 }
309
uno_Environment_invoke(uno_Environment * pEnv,uno_EnvCallee * pCallee,...)310 extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
311 SAL_THROW_EXTERN_C()
312 {
313 va_list param;
314
315 va_start(param, pCallee);
316 uno_Environment_invoke_v(pEnv, pCallee, ¶m);
317 va_end(param);
318 }
319
uno_Environment_enter(uno_Environment * pTargetEnv)320 extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
321 SAL_THROW_EXTERN_C()
322 {
323 uno_Environment * pNextEnv = NULL;
324 uno_Environment * pCurrEnv = s_getCurrent();
325
326 int res;
327 while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
328 {
329 cppu::Enterable * pEnterable;
330
331 switch(res)
332 {
333 case -1:
334 pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
335 if (pEnterable)
336 pEnterable->leave();
337 pCurrEnv->release(pCurrEnv);
338 break;
339
340 case 1:
341 pNextEnv->acquire(pNextEnv);
342 pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
343 if (pEnterable)
344 pEnterable->enter();
345 break;
346 }
347
348 s_setCurrent(pNextEnv);
349 pCurrEnv = pNextEnv;
350 }
351 }
352
uno_Environment_isValid(uno_Environment * pEnv,rtl_uString ** pReason)353 int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
354 SAL_THROW_EXTERN_C()
355 {
356 int result = 1;
357
358 rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
359 if (typeName.equals(s_uno_envDcp))
360 {
361 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
362 if (pEnterable)
363 result = pEnterable->isValid((rtl::OUString *)pReason);
364 }
365 else
366 {
367 rtl::OUString envDcp(s_uno_envDcp);
368 envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);
369
370 uno::Environment env(envDcp);
371
372 result = env.isValid((rtl::OUString *)pReason);
373 }
374
375 return result;
376 }
377