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, ¶m); 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, ¶m); 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, ¶m); 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