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