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