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 23162 : static bool relatesToInterface(typelib_TypeDescription * pTypeDescr)
44 : {
45 23162 : switch (pTypeDescr->eTypeClass)
46 : {
47 : // case typelib_TypeClass_TYPEDEF:
48 : case typelib_TypeClass_SEQUENCE:
49 : {
50 36 : switch (((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 4 : typelib_TypeDescription * pTD = 0;
60 4 : TYPELIB_DANGER_GET( &pTD, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType );
61 4 : bool bRel = relatesToInterface( pTD );
62 4 : TYPELIB_DANGER_RELEASE( pTD );
63 4 : return bRel;
64 : }
65 : default:
66 : ;
67 : }
68 32 : return false;
69 : }
70 : case typelib_TypeClass_STRUCT:
71 : case typelib_TypeClass_EXCEPTION:
72 : {
73 : // ...optimized... to avoid getDescription() calls!
74 6 : typelib_CompoundTypeDescription * pComp = (typelib_CompoundTypeDescription *)pTypeDescr;
75 6 : typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs;
76 16 : for ( sal_Int32 nPos = pComp->nMembers; nPos--; )
77 : {
78 10 : switch (pTypes[nPos]->eTypeClass)
79 : {
80 : case typelib_TypeClass_INTERFACE:
81 : case typelib_TypeClass_ANY: // might relate to interface
82 6 : 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 0 : if (pComp->pBaseTypeDescription)
100 0 : return relatesToInterface( (typelib_TypeDescription *)pComp->pBaseTypeDescription );
101 0 : break;
102 : }
103 : case typelib_TypeClass_ANY: // might relate to interface
104 : case typelib_TypeClass_INTERFACE:
105 998 : return true;
106 :
107 : default:
108 : ;
109 : }
110 22122 : return false;
111 : }
112 :
113 13834 : 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 13834 : Proxy * pThis = static_cast<Proxy *>(pUnoI);
122 :
123 : typelib_MethodParameter param;
124 13834 : sal_Int32 nParams = 0;
125 13834 : typelib_MethodParameter * pParams = 0;
126 13834 : typelib_TypeDescriptionReference * pReturnTypeRef = 0;
127 : // sal_Int32 nOutParams = 0;
128 :
129 13834 : switch (pMemberType->eTypeClass)
130 : {
131 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
132 0 : if (pReturn)
133 : {
134 : pReturnTypeRef =
135 : ((typelib_InterfaceAttributeTypeDescription *)
136 0 : pMemberType)->pAttributeTypeRef;
137 0 : nParams = 0;
138 0 : pParams = NULL;
139 : }
140 : else
141 : {
142 : param.pTypeRef = ((typelib_InterfaceAttributeTypeDescription *)
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 * method_td =
153 13834 : (typelib_InterfaceMethodTypeDescription *) pMemberType;
154 13834 : pReturnTypeRef = method_td->pReturnTypeRef;
155 13834 : nParams = method_td->nParams;
156 13834 : pParams = method_td->pParams;
157 13834 : 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 13834 : ppException );
171 13834 : }}
172 :
173 250 : extern "C" void SAL_CALL Proxy_free(SAL_UNUSED_PARAMETER uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C()
174 : {
175 250 : Proxy * pThis = static_cast<Proxy * >(reinterpret_cast<uno_Interface *>(pProxy));
176 250 : delete pThis;
177 250 : }
178 :
179 : extern "C" {
180 482 : static void SAL_CALL s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
181 : {
182 482 : Proxy * pProxy = static_cast<Proxy *>(pUnoI);
183 482 : pProxy->acquire();
184 482 : }
185 :
186 728 : static void SAL_CALL s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C()
187 : {
188 728 : Proxy * pProxy = static_cast<Proxy *>(pUnoI);
189 728 : pProxy->release();
190 728 : }
191 :
192 296 : static void s_acquireAndRegister_v(va_list * pParam)
193 : {
194 296 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
195 296 : rtl_uString * pOid = va_arg(*pParam, rtl_uString *);
196 296 : typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *);
197 296 : uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
198 :
199 296 : pUnoI->acquire(pUnoI);
200 296 : pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr);
201 296 : }
202 : }
203 :
204 296 : 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 296 : m_pProbeContext(pProbeContext)
223 : {
224 : LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::Proxy(<>)", this));
225 :
226 296 : typelib_typedescription_acquire((typelib_TypeDescription *)m_pTypeDescr);
227 296 : if (!((typelib_TypeDescription *)m_pTypeDescr)->bComplete)
228 0 : typelib_typedescription_complete((typelib_TypeDescription **)&m_pTypeDescr);
229 :
230 : OSL_ENSURE(((typelib_TypeDescription *)m_pTypeDescr)->bComplete, "### type is incomplete!");
231 :
232 296 : uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get());
233 :
234 : // uno_Interface
235 296 : uno_Interface::acquire = s_Proxy_acquire;
236 296 : uno_Interface::release = s_Proxy_release;
237 296 : uno_Interface::pDispatcher = s_Proxy_dispatch;
238 296 : }
239 :
240 250 : extern "C" { static void s_releaseAndRevoke_v(va_list * pParam)
241 : {
242 250 : uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
243 250 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
244 :
245 250 : pEnv->revokeInterface(pEnv, reinterpret_cast<void *>(pUnoI));
246 250 : pUnoI->release(pUnoI);
247 250 : }}
248 :
249 500 : Proxy::~Proxy()
250 : {
251 : LOG_LIFECYCLE_Proxy_emit(fprintf(stderr, "LIFE: %s -> %p\n", "Proxy::~Proxy()", this));
252 :
253 250 : uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI);
254 :
255 250 : typelib_typedescription_release((typelib_TypeDescription *)m_pTypeDescr);
256 250 : }
257 :
258 4 : static uno::TypeDescription getAcquireMethod(void)
259 : {
260 : typelib_TypeDescriptionReference * type_XInterface =
261 4 : * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
262 :
263 4 : typelib_TypeDescription * pTXInterfaceDescr = 0;
264 4 : TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
265 : uno::TypeDescription acquire(
266 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
267 4 : pTXInterfaceDescr)->ppAllMembers[1]);
268 4 : TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
269 :
270 4 : return acquire;
271 : }
272 :
273 4 : static uno::TypeDescription getReleaseMethod(void)
274 : {
275 : typelib_TypeDescriptionReference * type_XInterface =
276 4 : * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE);
277 :
278 4 : typelib_TypeDescription * pTXInterfaceDescr = 0;
279 4 : TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface);
280 : uno::TypeDescription release(
281 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
282 4 : pTXInterfaceDescr)->ppAllMembers[2]);
283 4 : TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
284 :
285 4 : return release;
286 : }
287 :
288 4 : static uno::TypeDescription s_acquireMethod(getAcquireMethod());
289 4 : static uno::TypeDescription s_releaseMethod(getReleaseMethod());
290 :
291 482 : void Proxy::acquire(void)
292 : {
293 482 : 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 482 : 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 482 : 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 482 : }
330 :
331 728 : void Proxy::release(void)
332 : {
333 728 : cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun;
334 728 : void * pProbeContext = m_pProbeContext;
335 :
336 728 : 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 728 : if (osl_atomic_decrement(&m_nRef) == 0)
349 250 : m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this);
350 :
351 728 : 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 728 : }
364 :
365 :
366 : extern "C" {
367 1004 : static void s_type_destructData_v(va_list * pParam)
368 : {
369 1004 : void * ret = va_arg(*pParam, void *);
370 1004 : typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *);
371 :
372 1004 : uno_type_destructData(ret, pReturnTypeRef, 0);
373 1004 : }
374 :
375 13834 : static void s_dispatcher_v(va_list * pParam)
376 : {
377 13834 : uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *);
378 13834 : typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *);
379 13834 : void * pReturn = va_arg(*pParam, void *);
380 13834 : void ** pArgs = va_arg(*pParam, void **);
381 13834 : uno_Any ** ppException = va_arg(*pParam, uno_Any **);
382 :
383 13834 : pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException);
384 13834 : }
385 : }
386 :
387 13834 : 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 13834 : 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 13834 : void ** args = (void **) alloca( sizeof (void *) * nParams );
408 :
409 13834 : typelib_TypeDescription * return_td = 0;
410 13834 : void * ret = pReturn;
411 13834 : if (pReturnTypeRef)
412 : {
413 13834 : TYPELIB_DANGER_GET(&return_td, pReturnTypeRef);
414 :
415 13834 : if (relatesToInterface(return_td))
416 930 : ret = alloca(return_td->nSize);
417 :
418 13834 : TYPELIB_DANGER_RELEASE(return_td);
419 : }
420 :
421 23158 : for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
422 : {
423 9324 : typelib_MethodParameter const & param = pParams[nPos];
424 9324 : typelib_TypeDescription * td = 0;
425 9324 : TYPELIB_DANGER_GET( &td, param.pTypeRef );
426 9324 : if (relatesToInterface(td))
427 : {
428 74 : args[nPos] = alloca(td->nSize);
429 74 : if (param.bIn)
430 : {
431 74 : uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get());
432 : }
433 : }
434 : else
435 : {
436 9250 : args[nPos] = pArgs[nPos];
437 : }
438 9324 : TYPELIB_DANGER_RELEASE( td );
439 : }
440 :
441 : uno_Any exc_data;
442 13834 : uno_Any * exc = &exc_data;
443 :
444 : // do the UNO call...
445 13834 : uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc);
446 :
447 13834 : if (exc == 0)
448 : {
449 23158 : for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos)
450 : {
451 9324 : if (args[nPos] != pArgs[nPos])
452 : {
453 74 : typelib_MethodParameter const & param = pParams[nPos];
454 74 : 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 74 : uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0);
466 : }
467 : }
468 13834 : if (ret != pReturn)
469 : {
470 : uno_type_copyAndConvertData(pReturn,
471 : ret,
472 : pReturnTypeRef,
473 930 : m_to_from.get());
474 :
475 930 : uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0);
476 : }
477 :
478 13834 : *ppException = 0;
479 : }
480 : else // exception occurred
481 : {
482 0 : 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 0 : m_to_from.get());
498 :
499 : // FIXME: need to destruct in m_to
500 0 : uno_any_destruct(exc, 0);
501 : }
502 :
503 13834 : 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 13846 : }
515 :
516 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|