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_bridges.hxx"
30 
31 #include <malloc.h>
32 
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include <uno/data.h>
35 
36 #include "bridges/cpp_uno/shared/bridge.hxx"
37 #include "bridges/cpp_uno/shared/types.hxx"
38 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
39 #include "bridges/cpp_uno/shared/vtables.hxx"
40 
41 #include "msci.hxx"
42 
43 using namespace ::rtl;
44 using namespace ::com::sun::star::uno;
45 
46 namespace
47 {
48 
49 //==================================================================================================
50 inline static void callVirtualMethod(
51 	void * pAdjustedThisPtr, sal_Int32 nVtableIndex,
52 	void * pRegisterReturn, typelib_TypeClass eReturnTypeClass,
53 	sal_Int32 * pStackLongs, sal_Int32 nStackLongs )
54 {
55 	// parameter list is mixed list of * and values
56 	// reference parameters are pointers
57 
58 	OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" );
59 	OSL_ENSURE( (sizeof(void *) == 4) &&
60 				 (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
61 
62 __asm
63 	{
64 		mov		eax, nStackLongs
65 		test	eax, eax
66 		je		Lcall
67 		// copy values
68 		mov		ecx, eax
69 		shl		eax, 2			 // sizeof(sal_Int32) == 4
70 		add		eax, pStackLongs // params stack space
71 Lcopy:	sub		eax, 4
72 		push	dword ptr [eax]
73 		dec		ecx
74 		jne		Lcopy
75 Lcall:
76 		// call
77 		mov		ecx, pAdjustedThisPtr
78 		push	ecx				// this ptr
79 		mov		edx, [ecx]		// pvft
80 		mov		eax, nVtableIndex
81 		shl		eax, 2			// sizeof(void *) == 4
82 		add		edx, eax
83 		call	[edx]			// interface method call must be __cdecl!!!
84 
85 		// register return
86 		mov		ecx, eReturnTypeClass
87 		cmp		ecx, typelib_TypeClass_VOID
88 		je		Lcleanup
89 		mov		ebx, pRegisterReturn
90 // int32
91 		cmp		ecx, typelib_TypeClass_LONG
92 		je		Lint32
93 		cmp		ecx, typelib_TypeClass_UNSIGNED_LONG
94 		je		Lint32
95 		cmp		ecx, typelib_TypeClass_ENUM
96 		je		Lint32
97 // int8
98 		cmp		ecx, typelib_TypeClass_BOOLEAN
99 		je		Lint8
100 		cmp		ecx, typelib_TypeClass_BYTE
101 		je		Lint8
102 // int16
103 		cmp		ecx, typelib_TypeClass_CHAR
104 		je		Lint16
105 		cmp		ecx, typelib_TypeClass_SHORT
106 		je		Lint16
107 		cmp		ecx, typelib_TypeClass_UNSIGNED_SHORT
108 		je		Lint16
109 // float
110 		cmp		ecx, typelib_TypeClass_FLOAT
111 		je		Lfloat
112 // double
113 		cmp		ecx, typelib_TypeClass_DOUBLE
114 		je		Ldouble
115 // int64
116 		cmp		ecx, typelib_TypeClass_HYPER
117 		je		Lint64
118 		cmp		ecx, typelib_TypeClass_UNSIGNED_HYPER
119   		je		Lint64
120 		jmp		Lcleanup // no simple type
121 Lint8:
122 		mov		byte ptr [ebx], al
123 		jmp		Lcleanup
124 Lint16:
125 		mov		word ptr [ebx], ax
126 		jmp		Lcleanup
127 Lfloat:
128 		fstp	dword ptr [ebx]
129 		jmp		Lcleanup
130 Ldouble:
131 		fstp	qword ptr [ebx]
132 		jmp		Lcleanup
133 Lint64:
134 		mov		dword ptr [ebx], eax
135 		mov		dword ptr [ebx+4], edx
136 		jmp		Lcleanup
137 Lint32:
138 		mov		dword ptr [ebx], eax
139 		jmp		Lcleanup
140 Lcleanup:
141 		// cleanup stack (obsolete though because of function)
142 		mov		eax, nStackLongs
143 		shl		eax, 2			// sizeof(sal_Int32) == 4
144 		add		eax, 4			// this ptr
145 		add		esp, eax
146 	}
147 }
148 
149 //==================================================================================================
150 static void cpp_call(
151 	bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
152 	bridges::cpp_uno::shared::VtableSlot aVtableSlot,
153 	typelib_TypeDescriptionReference * pReturnTypeRef,
154 	sal_Int32 nParams, typelib_MethodParameter * pParams,
155 	void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) throw ()
156 {
157 	// max space for: [complex ret ptr], values|ptr ...
158 	char * pCppStack		= (char *)alloca( sizeof(sal_Int32) + (nParams * sizeof(sal_Int64)) );
159 	char * pCppStackStart	= pCppStack;
160 
161 	// return
162 	typelib_TypeDescription * pReturnTypeDescr = 0;
163 	TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
164 	OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
165 
166 	void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
167 
168 	if (pReturnTypeDescr)
169 	{
170 		if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
171 		{
172 			pCppReturn = pUnoReturn; // direct way for simple types
173 		}
174 		else
175 		{
176 			// complex return via ptr
177 			pCppReturn = *(void **)pCppStack
178                 = (bridges::cpp_uno::shared::relatesToInterfaceType(
179                        pReturnTypeDescr )
180                    ? alloca( pReturnTypeDescr->nSize )
181                    : pUnoReturn); // direct way
182 			pCppStack += sizeof(void *);
183 		}
184 	}
185 
186 	// stack space
187 
188 	OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
189 	// args
190 	void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
191 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
192 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
193 	// type descriptions for reconversions
194 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
195 
196 	sal_Int32 nTempIndizes   = 0;
197 
198 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
199 	{
200 		const typelib_MethodParameter & rParam = pParams[nPos];
201 		typelib_TypeDescription * pParamTypeDescr = 0;
202 		TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
203 
204 		if (!rParam.bOut
205             && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
206 		{
207 			::uno_copyAndConvertData(
208                 pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
209                 pThis->getBridge()->getUno2Cpp() );
210 
211 			switch (pParamTypeDescr->eTypeClass)
212 			{
213 			case typelib_TypeClass_HYPER:
214 			case typelib_TypeClass_UNSIGNED_HYPER:
215 			case typelib_TypeClass_DOUBLE:
216 				pCppStack += sizeof(sal_Int32); // extra long
217                 break;
218             default:
219                 break;
220 			}
221 			// no longer needed
222 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
223 		}
224 		else // ptr to complex value | ref
225 		{
226 			if (! rParam.bIn) // is pure out
227 			{
228 				// cpp out is constructed mem, uno out is not!
229 				::uno_constructData(
230 					*(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
231 					pParamTypeDescr );
232 				pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
233 				// will be released at reconversion
234 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
235 			}
236 			// is in/inout
237 			else if (bridges::cpp_uno::shared::relatesToInterfaceType(
238                          pParamTypeDescr ))
239 			{
240 				::uno_copyAndConvertData(
241 					*(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
242 					pUnoArgs[nPos], pParamTypeDescr,
243 					pThis->getBridge()->getUno2Cpp() );
244 
245 				pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
246 				// will be released at reconversion
247 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
248 			}
249 			else // direct way
250 			{
251 				*(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
252 				// no longer needed
253 				TYPELIB_DANGER_RELEASE( pParamTypeDescr );
254 			}
255 		}
256 		pCppStack += sizeof(sal_Int32); // standard parameter length
257 	}
258 
259     __try
260     {
261         // pCppI is msci this pointer
262         callVirtualMethod(
263             reinterpret_cast< void ** >(pThis->getCppI()) + aVtableSlot.offset,
264             aVtableSlot.index,
265             pCppReturn, pReturnTypeDescr->eTypeClass,
266             (sal_Int32 *)pCppStackStart,
267             (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
268     }
269     __except (CPPU_CURRENT_NAMESPACE::msci_filterCppException(
270                   GetExceptionInformation(),
271                   *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
272    {
273         // *ppUnoExc was constructed by filter function
274         // temporary params
275         while (nTempIndizes--)
276         {
277             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
278             // destroy temp cpp param => cpp: every param was constructed
279             ::uno_destructData(
280                 pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes],
281                 cpp_release );
282             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
283         }
284 		// return type
285 		if (pReturnTypeDescr)
286         {
287 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
288         }
289         // end here
290         return;
291 	}
292 
293     // NO exception occured
294     *ppUnoExc = 0;
295 
296     // reconvert temporary params
297     while (nTempIndizes--)
298     {
299         sal_Int32 nIndex = pTempIndizes[nTempIndizes];
300         typelib_TypeDescription * pParamTypeDescr =
301             ppTempParamTypeDescr[nTempIndizes];
302 
303         if (pParams[nIndex].bIn)
304         {
305             if (pParams[nIndex].bOut) // inout
306             {
307                 ::uno_destructData(
308                     pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
309                 ::uno_copyAndConvertData(
310                     pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
311                     pThis->getBridge()->getCpp2Uno() );
312             }
313         }
314         else // pure out
315         {
316             ::uno_copyAndConvertData(
317                 pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
318                 pThis->getBridge()->getCpp2Uno() );
319         }
320         // destroy temp cpp param => cpp: every param was constructed
321         ::uno_destructData(
322             pCppArgs[nIndex], pParamTypeDescr, cpp_release );
323 
324         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
325     }
326     // return value
327     if (pCppReturn && pUnoReturn != pCppReturn)
328     {
329         ::uno_copyAndConvertData(
330             pUnoReturn, pCppReturn, pReturnTypeDescr,
331             pThis->getBridge()->getCpp2Uno() );
332         ::uno_destructData(
333             pCppReturn, pReturnTypeDescr, cpp_release );
334     }
335     // return type
336     if (pReturnTypeDescr)
337     {
338         TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
339     }
340 }
341 
342 }
343 
344 namespace bridges { namespace cpp_uno { namespace shared {
345 
346 void unoInterfaceProxyDispatch(
347 	uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
348     void * pReturn, void * pArgs[], uno_Any ** ppException )
349 {
350 	// is my surrogate
351 	bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
352         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
353 
354 	switch (pMemberDescr->eTypeClass)
355 	{
356 	case typelib_TypeClass_INTERFACE_ATTRIBUTE:
357 	{
358         VtableSlot aVtableSlot(
359             getVtableSlot(
360                 reinterpret_cast<
361                     typelib_InterfaceAttributeTypeDescription const * >(
362                         pMemberDescr)));
363 		if (pReturn)
364 		{
365 			// dependent dispatch
366 			cpp_call(
367 				pThis, aVtableSlot,
368 				((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
369 				0, 0, // no params
370 				pReturn, pArgs, ppException );
371 		}
372 		else
373 		{
374 			// is SET
375 			typelib_MethodParameter aParam;
376 			aParam.pTypeRef =
377 				((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
378 			aParam.bIn		= sal_True;
379 			aParam.bOut		= sal_False;
380 
381 			typelib_TypeDescriptionReference * pReturnTypeRef = 0;
382 			OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
383 			typelib_typedescriptionreference_new(
384 				&pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
385 
386 			// dependent dispatch
387             aVtableSlot.index += 1; // get, then set method
388 			cpp_call(
389 				pThis, aVtableSlot,
390 				pReturnTypeRef,
391 				1, &aParam,
392 				pReturn, pArgs, ppException );
393 
394 			typelib_typedescriptionreference_release( pReturnTypeRef );
395 		}
396 
397 		break;
398 	}
399 	case typelib_TypeClass_INTERFACE_METHOD:
400 	{
401         VtableSlot aVtableSlot(
402             getVtableSlot(
403                 reinterpret_cast<
404                     typelib_InterfaceMethodTypeDescription const * >(
405                         pMemberDescr)));
406 		switch (aVtableSlot.index)
407 		{
408 			// standard calls
409 		case 1: // acquire uno interface
410 			(*pUnoI->acquire)( pUnoI );
411 			*ppException = 0;
412 			break;
413 		case 2: // release uno interface
414 			(*pUnoI->release)( pUnoI );
415 			*ppException = 0;
416 			break;
417 		case 0: // queryInterface() opt
418 		{
419 			typelib_TypeDescription * pTD = 0;
420 			TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
421 			if (pTD)
422             {
423                 uno_Interface * pInterface = 0;
424                 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
425                     pThis->pBridge->getUnoEnv(),
426                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
427 
428                 if (pInterface)
429                 {
430                     ::uno_any_construct(
431                         reinterpret_cast< uno_Any * >( pReturn ),
432                         &pInterface, pTD, 0 );
433                     (*pInterface->release)( pInterface );
434                     TYPELIB_DANGER_RELEASE( pTD );
435                     *ppException = 0;
436                     break;
437                 }
438                 TYPELIB_DANGER_RELEASE( pTD );
439             }
440 		} // else perform queryInterface()
441 		default:
442 			// dependent dispatch
443 			cpp_call(
444 				pThis, aVtableSlot,
445 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
446 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
447 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
448 				pReturn, pArgs, ppException );
449 		}
450 		break;
451 	}
452 	default:
453 	{
454 		::com::sun::star::uno::RuntimeException aExc(
455 			OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
456 			::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
457 
458 		Type const & rExcType = ::getCppuType( &aExc );
459 		// binary identical null reference
460 		::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
461 	}
462 	}
463 }
464 
465 } } }
466