xref: /aoo41x/main/cppu/source/uno/EnvStack.cxx (revision 129fa3d1)
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 
43 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 
56 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 
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 
80 	else
81 	{
82 		ThreadMap::iterator iEnv = s_threadMap.find(threadId);
83 		s_threadMap.erase(iEnv);
84 	}
85 }
86 
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 
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 
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 
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 
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 
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 
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, &param);
240 	va_end(param);
241 }
242 
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 
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, &param);
259 	va_end(param);
260 }
261 
262 static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
263 
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 
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 
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 
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, &param);
317 	va_end(param);
318 }
319 
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 
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