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 :
21 : #include "Proxy.hxx"
22 :
23 : #include "sal/alloca.h"
24 : #include "uno/dispatcher.h"
25 : #include "typelib/typedescription.hxx"
26 : #include "cppu/EnvDcp.hxx"
27 :
28 :
29 : //#define LOG_LIFECYCLE_Proxy
30 : #ifdef LOG_LIFECYCLE_Proxy
31 : # include <iostream>
32 : # define LOG_LIFECYCLE_Proxy_emit(x) x
33 :
34 : #else
35 : # define LOG_LIFECYCLE_Proxy_emit(x)
36 :
37 : #endif
38 :
39 :
40 : using namespace com::sun::star;
41 :
42 :
43 589650 : static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
44 : {
45 589650 : switch (pTypeDescr->eTypeClass)
46 : {
47 : // case typelib_TypeClass_TYPEDEF:
48 : case typelib_TypeClass_SEQUENCE:
49 : {
50 176 : switch (reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType->eTypeClass)
51 : {
52 : case typelib_TypeClass_INTERFACE:
53 : case typelib_TypeClass_ANY: // might relate to interface
54 0 : return true;
55 : case typelib_TypeClass_SEQUENCE:
56 : case typelib_TypeClass_STRUCT:
57 : case typelib_TypeClass_EXCEPTION:
58 : {
59 15 : typelib_TypeDescription * pTD = 0;
60 15 : TYPELIB_DANGER_GET( &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType );
61 15 : bool bRel = relatesToInterface( pTD );
62 15 : TYPELIB_DANGER_RELEASE( pTD );
63 15 : return bRel;
64 : }
65 : default:
66 : ;
67 : }
68 161 : return false;
69 : }
70 : case typelib_TypeClass_STRUCT:
71 : case typelib_TypeClass_EXCEPTION:
72 : {
73 : // ...optimized... to avoid getDescription() calls!
74 60 : typelib_CompoundTypeDescription * pComp = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr);
75 60 : typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
76 243 : for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
77 : {
78 147 : switch (pTypes[nPos]->eTypeClass)
79 : {
80 : case typelib_TypeClass_INTERFACE:
81 : case typelib_TypeClass_ANY: // might relate to interface
82 24 : return true;
83 : // case typelib_TypeClass_TYPEDEF:
84 : case typelib_TypeClass_SEQUENCE:
85 : case typelib_TypeClass_STRUCT:
86 : case typelib_TypeClass_EXCEPTION:
87 : {
88 0 : typelib_TypeDescription * pTD = 0;
89 0 : TYPELIB_DANGER_GET( &pTD, pTypes[nPos] );
90 0 : bool bRel = relatesToInterface( pTD );
91 0 : TYPELIB_DANGER_RELEASE( pTD );
92 0 : if (bRel)
93 0 : return true;
94 : }
95 : default:
96 : ;
97 : }
98 : }
99 36 : if (pComp->pBaseTypeDescription)
100 0 : return relatesToInterface( &pComp->pBaseTypeDescription->aBase );
101 36 : break;
102 : }
103 : case typelib_TypeClass_ANY: // might relate to interface
104 : case typelib_TypeClass_INTERFACE:
105 126144 : return true;
106 :
107 : default:
108 : ;
109 : }
110 463306 : return false;
111 : }
112 :
113 341489 : extern "C" { static void SAL_CALL s_Proxy_dispatch(
114 : uno_Interface * pUnoI,
115 : typelib_TypeDescription const * pMemberType,
116 : void * pReturn,
117 : void * pArgs[],
118 : uno_Any ** ppException)
119 : SAL_THROW_EXTERN_C()
120 : {
121 341489 : Proxy * pThis = static_cast<Proxy *>(pUnoI);
122 :
123 : typelib_MethodParameter param;
124 341489 : sal_Int32 nParams = 0;
125 341489 : typelib_MethodParameter * pParams = 0;
126 341489 : typelib_TypeDescriptionReference * pReturnTypeRef = 0;
127 : // sal_Int32 nOutParams = 0;
128 :
129 341489 : switch (pMemberType->eTypeClass)
130 : {
131 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
132 0 : if (pReturn)
133 : {
134 : pReturnTypeRef =
135 : reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
136 0 : pMemberType)->pAttributeTypeRef;
137 0 : nParams = 0;
138 0 : pParams = NULL;
139 : }
140 : else
141 : {
142 : param.pTypeRef = reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
143 0 : pMemberType)->pAttributeTypeRef;
144 0 : param.bIn = sal_True;
145 0 : param.bOut = sal_False;
146 0 : nParams = 1;
147 0 : pParams = ¶m;
148 : }
149 0 : break;
150 : case typelib_TypeClass_INTERFACE_METHOD:
151 : {
152 : typelib_InterfaceMethodTypeDescription const * method_td =
153 341489 : reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType);
154 341489 : pReturnTypeRef = method_td->pReturnTypeRef;
155 341489 : nParams = method_td->nParams;
156 341489 : pParams = method_td->pParams;
157 341489 : break;
158 : }
159 : default:
160 : OSL_FAIL( "### illegal member typeclass!" );
161 0 : abort();
162 : }
163 :
164 : pThis->dispatch( pReturnTypeRef,
165 : pParams,
166 : nParams,
167 : pMemberType,
168 : pReturn,
169 : pArgs,
170 341489 : ppException );
171 341489 : }}
172 :
173 96403 : extern "C" void SAL_CALL Proxy_free(SAL_UNUSED_PARAMETER uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
174 : {
175 96403 : Proxy * pThis = static_cast<Proxy * >(static_cast<uno_Interface *>(pProxy));
176 96403 : delete pThis;
177 96403 : }
178 :
179 : extern "C" {
180 99025 : static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
181 : {
182 99025 : Proxy * pProxy = static_cast<Proxy *>(pUnoI);
183 99025 : pProxy->acquire();
184 99025 : }
185 :
186 195428 : static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
187 : {
188 195428 : Proxy * pProxy = static_cast<Proxy *>(pUnoI);
189 195428 : pProxy->release();
190 195428 : }
191 :
192 96425 : static void s_acquireAndRegister_v(va_list * pParam)
193 : {
194 96425 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
195 96425 : rtl_uString * pOid = va_arg(*pParam, rtl_uString *);
196 96425 : typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
197 96425 : uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
198 :
199 96425 : pUnoI->acquire(pUnoI);
200 96425 : pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
201 96425 : }
202 : }
203 :
204 96425 : Proxy::Proxy(uno::Mapping const & to_from,
205 : uno_Environment * pTo,
206 : uno_Environment * pFrom,
207 : uno_Interface * pUnoI,
208 : typelib_InterfaceTypeDescription * pTypeDescr,
209 : rtl::OUString const & rOId,
210 : cppu::helper::purpenv::ProbeFun * probeFun,
211 : void * pProbeContext
212 : )
213 : : m_nRef (1),
214 : m_from (pFrom),
215 : m_to (pTo),
216 : m_from_to (pFrom, pTo),
217 : m_to_from (to_from),
218 : m_pUnoI (pUnoI),
219 : m_pTypeDescr (pTypeDescr),
220 : m_aOId (rOId),
221 : m_probeFun (probeFun),
222 96425 : m_pProbeContext(pProbeContext)
223 : {
224 : LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
225 :
226 96425 : typelib_typedescription_acquire(&m_pTypeDescr->aBase);
227 96425 : if (!m_pTypeDescr->aBase.bComplete)
228 0 : typelib_typedescription_complete(reinterpret_cast<typelib_TypeDescription **>(&m_pTypeDescr));
229 :
230 : OSL_ENSURE(m_pTypeDescr->aBase.bComplete, "### type is incomplete!");
231 :
232 96425 : uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
233 :
234 : // uno_Interface
235 96425 : uno_Interface::acquire = s_Proxy_acquire;
236 96425 : uno_Interface::release = s_Proxy_release;
237 96425 : uno_Interface::pDispatcher = s_Proxy_dispatch;
238 96425 : }
239 :
240 96403 : extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
241 : {
242 96403 : uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
243 96403 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
244 :
245 96403 : pEnv->revokeInterface(pEnv, pUnoI);
246 96403 : pUnoI->release(pUnoI);
247 96403 : }}
248 :
249 192806 : Proxy::~Proxy()
250 : {
251 : LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
252 :
253 96403 : uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
254 :
255 96403 : typelib_typedescription_release(&m_pTypeDescr->aBase);
256 96403 : }
257 :
258 5 : static uno::TypeDescription getAcquireMethod()
259 : {
260 : typelib_TypeDescriptionReference * type_XInterface =
261 5 : * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
262 :
263 5 : typelib_TypeDescription * pTXInterfaceDescr = 0;
264 5 : TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
265 : uno::TypeDescription acquire(
266 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
267 5 : pTXInterfaceDescr)->ppAllMembers[1]);
268 5 : TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
269 :
270 5 : return acquire;
271 : }
272 :
273 5 : static uno::TypeDescription getReleaseMethod()
274 : {
275 : typelib_TypeDescriptionReference * type_XInterface =
276 5 : * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
277 :
278 5 : typelib_TypeDescription * pTXInterfaceDescr = 0;
279 5 : TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
280 : uno::TypeDescription release(
281 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
282 5 : pTXInterfaceDescr)->ppAllMembers[2]);
283 5 : TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
284 :
285 5 : return release;
286 : }
287 :
288 5 : static uno::TypeDescription s_acquireMethod(getAcquireMethod());
289 5 : static uno::TypeDescription s_releaseMethod(getReleaseMethod());
290 :
291 99025 : void Proxy::acquire()
292 : {
293 99025 : if (m_probeFun)
294 : m_probeFun(true,
295 : this,
296 : m_pProbeContext,
297 0 : *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
298 : NULL,
299 : 0,
300 0 : s_acquireMethod.get(),
301 : NULL,
302 : NULL,
303 0 : NULL);
304 :
305 99025 : if (osl_atomic_increment(&m_nRef) == 1)
306 : {
307 : // rebirth of proxy zombie
308 0 : void * pThis = this;
309 0 : m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv,
310 : &pThis,
311 : Proxy_free,
312 : m_aOId.pData,
313 0 : m_pTypeDescr);
314 : OSL_ASSERT(pThis == this);
315 : }
316 :
317 99025 : if (m_probeFun)
318 : m_probeFun(false,
319 : this,
320 : m_pProbeContext,
321 0 : *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
322 : NULL,
323 : 0,
324 0 : s_acquireMethod.get(),
325 : NULL,
326 : NULL,
327 0 : NULL);
328 :
329 99025 : }
330 :
331 195428 : void Proxy::release()
332 : {
333 195428 : cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
334 195428 : void * pProbeContext = m_pProbeContext;
335 :
336 195428 : if (m_probeFun)
337 : m_probeFun(true,
338 : this,
339 : m_pProbeContext,
340 0 : *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
341 : NULL,
342 : 0,
343 0 : s_releaseMethod.get(),
344 : NULL,
345 : NULL,
346 0 : NULL);
347 :
348 195428 : if (osl_atomic_decrement(&m_nRef) == 0)
349 96403 : m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
350 :
351 195428 : if (probeFun)
352 : probeFun(false,
353 : this,
354 : pProbeContext,
355 0 : *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID),
356 : NULL,
357 : 0,
358 0 : s_releaseMethod.get(),
359 : NULL,
360 : NULL,
361 0 : NULL);
362 :
363 195428 : }
364 :
365 :
366 : extern "C" {
367 126168 : static void s_type_destructData_v(va_list * pParam)
368 : {
369 126168 : void * ret = va_arg(*pParam, void *);
370 126168 : typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
371 :
372 126168 : uno_type_destructData(ret, pReturnTypeRef, 0);
373 126168 : }
374 :
375 341489 : static void s_dispatcher_v(va_list * pParam)
376 : {
377 341489 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
378 341489 : typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
379 341489 : void * pReturn = va_arg(*pParam, void *);
380 341489 : void ** pArgs = va_arg(*pParam, void **);
381 341489 : uno_Any ** ppException = va_arg(*pParam, uno_Any **);
382 :
383 341489 : pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
384 341489 : }
385 : }
386 :
387 341489 : void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef,
388 : typelib_MethodParameter * pParams,
389 : sal_Int32 nParams,
390 : typelib_TypeDescription const * pMemberType,
391 : void * pReturn,
392 : void * pArgs[],
393 : uno_Any ** ppException)
394 : {
395 341489 : if (m_probeFun)
396 : m_probeFun(true,
397 : this,
398 : m_pProbeContext,
399 : pReturnTypeRef,
400 : pParams,
401 : nParams,
402 : pMemberType,
403 : pReturn,
404 : pArgs,
405 0 : ppException);
406 :
407 341489 : void ** args = static_cast<void **>(alloca( sizeof (void *) * nParams ));
408 :
409 341489 : typelib_TypeDescription * return_td = 0;
410 341489 : void * ret = pReturn;
411 341489 : if (pReturnTypeRef)
412 : {
413 341489 : TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
414 :
415 341489 : if (relatesToInterface(return_td))
416 125816 : ret = alloca(return_td->nSize);
417 :
418 341489 : TYPELIB_DANGER_RELEASE(return_td);
419 : }
420 :
421 589635 : for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
422 : {
423 248146 : typelib_MethodParameter const & param = pParams[nPos];
424 248146 : typelib_TypeDescription * td = 0;
425 248146 : TYPELIB_DANGER_GET( &td, param.pTypeRef );
426 248146 : if (relatesToInterface(td))
427 : {
428 352 : args[nPos] = alloca(td->nSize);
429 352 : if (param.bIn)
430 : {
431 352 : uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
432 : }
433 : }
434 : else
435 : {
436 247794 : args[nPos] = pArgs[nPos];
437 : }
438 248146 : TYPELIB_DANGER_RELEASE( td );
439 : }
440 :
441 : uno_Any exc_data;
442 341489 : uno_Any * exc = &exc_data;
443 :
444 : // do the UNO call...
445 341489 : uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
446 :
447 341489 : if (exc == 0)
448 : {
449 589475 : for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
450 : {
451 248146 : if (args[nPos] != pArgs[nPos])
452 : {
453 352 : typelib_MethodParameter const & param = pParams[nPos];
454 352 : if (param.bOut)
455 : {
456 0 : if (param.bIn) // is inout
457 : {
458 0 : uno_type_destructData(pArgs[nPos], param.pTypeRef, 0);
459 : }
460 0 : uno_type_copyAndConvertData(pArgs[ nPos ],
461 0 : args[ nPos ],
462 : param.pTypeRef,
463 0 : m_to_from.get());
464 : }
465 352 : uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
466 : }
467 : }
468 341329 : if (ret != pReturn)
469 : {
470 : uno_type_copyAndConvertData(pReturn,
471 : ret,
472 : pReturnTypeRef,
473 125816 : m_to_from.get());
474 :
475 125816 : uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
476 : }
477 :
478 341329 : *ppException = 0;
479 : }
480 : else // exception occurred
481 : {
482 160 : for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
483 : {
484 0 : if (args[nPos] != pArgs[nPos])
485 : {
486 0 : typelib_MethodParameter const & param = pParams[nPos];
487 0 : if (param.bIn)
488 : {
489 0 : uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
490 : }
491 : }
492 : }
493 :
494 : uno_type_any_constructAndConvert(*ppException,
495 : exc->pData,
496 : exc->pType,
497 160 : m_to_from.get());
498 :
499 : // FIXME: need to destruct in m_to
500 160 : uno_any_destruct(exc, 0);
501 : }
502 :
503 341489 : if (m_probeFun)
504 : m_probeFun(false,
505 : this,
506 : m_pProbeContext,
507 : pReturnTypeRef,
508 : pParams,
509 : nParams,
510 : pMemberType,
511 : pReturn,
512 : pArgs,
513 0 : ppException);
514 341504 : }
515 :
516 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|