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 "abi.hxx"
38 #include "mscx.hxx"
39 
40 using namespace ::rtl;
41 using namespace ::com::sun::star::uno;
42 
43 namespace
44 {
45 
46 //==================================================================================================
47 extern "C" void callVirtualMethod(
48 	void * pAdjustedThisPtr, sal_Int32 nVtableIndex,
49 	void * pRegisterReturn, typelib_TypeClass eReturnTypeClass,
50 	sal_uInt64 * pStackLongs, sal_uInt32 nStackLongs );
51 
52 //==================================================================================================
cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,bridges::cpp_uno::shared::VtableSlot aVtableSlot,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void * pUnoReturn,void * pUnoArgs[],uno_Any ** ppUnoExc)53 static void cpp_call(
54 	bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
55 	bridges::cpp_uno::shared::VtableSlot aVtableSlot,
56 	typelib_TypeDescriptionReference * pReturnTypeRef,
57 	sal_Int32 nParams, typelib_MethodParameter * pParams,
58 	void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) throw ()
59 {
60 	// max space for: [complex ret ptr], values|ptr ...
61 	sal_uInt64 *pStack = (sal_uInt64 *)alloca( (nParams + 3) * sizeof(sal_uInt64) );
62 	sal_uInt64 *pStackStart	= pStack;
63 
64 	// Push "this" pointer
65 	void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
66 	*pStack++ = *(sal_uInt64*)&pAdjustedThisPtr;
67 
68 	// return
69 	typelib_TypeDescription * pReturnTypeDescr = 0;
70 	TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
71 	OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
72 
73 	void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
74 
75 	if ( pReturnTypeDescr )
76 	{
77 		if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
78 		{
79 			// complex return via ptr
80 			pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
81 						 alloca( pReturnTypeDescr->nSize ) : pUnoReturn; // direct way
82 			*pStack++ = *(sal_uInt64*)&pCppReturn;
83 		}
84 		else
85 			pCppReturn = pUnoReturn; // direct way for simple types
86 	}
87 
88 	// Args
89 	void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
90 	// Indices of values this have to be converted (interface conversion cpp<=>uno)
91 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
92 	// Type descriptions for reconversions
93 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
94 
95 	sal_Int32 nTempIndizes = 0;
96 
97 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
98 	{
99 		const typelib_MethodParameter & rParam = pParams[nPos];
100 		typelib_TypeDescription * pParamTypeDescr = 0;
101 		TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
102 
103 		if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
104 		{
105 			uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
106 									pThis->getBridge()->getUno2Cpp() );
107 
108 			switch (pParamTypeDescr->eTypeClass)
109 			{
110 			case typelib_TypeClass_HYPER:
111 			case typelib_TypeClass_UNSIGNED_HYPER:
112 				*pStack++ = *(sal_uInt64*)&pCppArgs[nPos];
113 				break;
114 			case typelib_TypeClass_LONG:
115 			case typelib_TypeClass_UNSIGNED_LONG:
116 			case typelib_TypeClass_ENUM:
117 				*pStack++ = *(sal_uInt32*)&pCppArgs[nPos];
118 				break;
119 			case typelib_TypeClass_SHORT:
120 			case typelib_TypeClass_UNSIGNED_SHORT:
121 			case typelib_TypeClass_CHAR:
122 				*pStack++ = *(sal_uInt16*)&pCppArgs[nPos];
123 				break;
124 			case typelib_TypeClass_BOOLEAN:
125 			case typelib_TypeClass_BYTE:
126 				*pStack++ = *(sal_uInt8*)&pCppArgs[nPos];
127 				break;
128 			case typelib_TypeClass_FLOAT:
129 			case typelib_TypeClass_DOUBLE:
130 				*pStack++ = *(sal_uInt64*)&pCppArgs[nPos]; // verbatim!
131                 break;
132             default:
133                 break;
134 			}
135 			// no longer needed
136 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
137 		}
138 		else // ptr to complex value | ref
139 		{
140 			if (! rParam.bIn) // is pure out
141 			{
142 				// cpp out is constructed mem, uno out is not!
143 				uno_constructData(
144 					pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
145 					pParamTypeDescr );
146 				pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
147 				// will be released at reconversion
148 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
149 			}
150 			// is in/inout
151 			else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
152 			{
153 				uno_copyAndConvertData(
154 					pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
155 					pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
156 
157 				pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
158 				// will be released at reconversion
159 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
160 			}
161 			else // direct way
162 			{
163 				pCppArgs[nPos] = pUnoArgs[nPos];
164 				// no longer needed
165 				TYPELIB_DANGER_RELEASE( pParamTypeDescr );
166 			}
167 			*pStack++ = *(sal_uInt64*)&pCppArgs[nPos];
168 		}
169 	}
170 
171     __try
172     {
173         // pCppI is mscx this pointer
174         callVirtualMethod(
175             pAdjustedThisPtr,
176             aVtableSlot.index,
177             pCppReturn, pReturnTypeDescr->eTypeClass,
178             pStackStart, (pStack - pStackStart) );
179     }
180     __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException(
181                   GetExceptionInformation(),
182                   *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
183    {
184         // *ppUnoExc was constructed by filter function
185         // temporary params
186         for ( ; nTempIndizes--; )
187         {
188             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
189             // destroy temp cpp param => cpp: every param was constructed
190             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
191             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
192         }
193 		// return type
194 		if (pReturnTypeDescr)
195 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
196         // end here
197         return;
198 	}
199 
200     // NO exception occurred
201     *ppUnoExc = 0;
202 
203     // reconvert temporary params
204     for ( ; nTempIndizes--; )
205     {
206         sal_Int32 nIndex = pTempIndizes[nTempIndizes];
207         typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
208 
209         if (pParams[nIndex].bIn)
210         {
211             if (pParams[nIndex].bOut) // inout
212             {
213                 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
214                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
215                                         pThis->getBridge()->getCpp2Uno() );
216             }
217         }
218         else // pure out
219         {
220             uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
221                                     pThis->getBridge()->getCpp2Uno() );
222         }
223         // destroy temp cpp param => cpp: every param was constructed
224         uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
225 
226         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
227     }
228     // return value
229     if (pCppReturn && pUnoReturn != pCppReturn)
230     {
231         uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
232                                 pThis->getBridge()->getCpp2Uno() );
233         uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
234     }
235     // return type
236     if (pReturnTypeDescr)
237         TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
238 }
239 
240 }
241 
242 namespace bridges { namespace cpp_uno { namespace shared {
243 
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)244 void unoInterfaceProxyDispatch(
245 	uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
246     void * pReturn, void * pArgs[], uno_Any ** ppException )
247 {
248 	// is my surrogate
249 	bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
250         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
251 
252 	switch (pMemberDescr->eTypeClass)
253 	{
254 	case typelib_TypeClass_INTERFACE_ATTRIBUTE:
255 	{
256         VtableSlot aVtableSlot(
257             getVtableSlot(
258                 reinterpret_cast<
259                     typelib_InterfaceAttributeTypeDescription const * >(
260                         pMemberDescr)));
261 
262 		if (pReturn)
263 		{
264 			// dependent dispatch
265 			cpp_call(
266 				pThis, aVtableSlot,
267 				((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
268 				0, 0, // no params
269 				pReturn, pArgs, ppException );
270 		}
271 		else
272 		{
273 			// is SET
274 			typelib_MethodParameter aParam;
275 			aParam.pTypeRef =
276 				((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
277 			aParam.bIn		= sal_True;
278 			aParam.bOut		= sal_False;
279 
280 			typelib_TypeDescriptionReference * pReturnTypeRef = 0;
281 			OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
282 			typelib_typedescriptionreference_new(
283 				&pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
284 
285 			// dependent dispatch
286             aVtableSlot.index += 1; // get, then set method
287 			cpp_call(
288 				pThis, aVtableSlot, // get, then set method
289 				pReturnTypeRef,
290 				1, &aParam,
291 				pReturn, pArgs, ppException );
292 
293 			typelib_typedescriptionreference_release( pReturnTypeRef );
294 		}
295 
296 		break;
297 	}
298 	case typelib_TypeClass_INTERFACE_METHOD:
299 	{
300         VtableSlot aVtableSlot(
301             getVtableSlot(
302                 reinterpret_cast<
303                     typelib_InterfaceMethodTypeDescription const * >(
304                         pMemberDescr)));
305 
306 		switch (aVtableSlot.index)
307 		{
308 			// standard calls
309 		case 1: // acquire uno interface
310 			(*pUnoI->acquire)( pUnoI );
311 			*ppException = 0;
312 			break;
313 		case 2: // release uno interface
314 			(*pUnoI->release)( pUnoI );
315 			*ppException = 0;
316 			break;
317 		case 0: // queryInterface() opt
318 		{
319 			typelib_TypeDescription * pTD = 0;
320 			TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
321 			if (pTD)
322             {
323                 uno_Interface * pInterface = 0;
324                 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
325                     pThis->getBridge()->getUnoEnv(),
326                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
327 
328                 if (pInterface)
329                 {
330                     ::uno_any_construct(
331                         reinterpret_cast< uno_Any * >( pReturn ),
332                         &pInterface, pTD, 0 );
333                     (*pInterface->release)( pInterface );
334                     TYPELIB_DANGER_RELEASE( pTD );
335                     *ppException = 0;
336                     break;
337                 }
338                 TYPELIB_DANGER_RELEASE( pTD );
339             }
340 		} // else perform queryInterface()
341 		default:
342 			// dependent dispatch
343 			cpp_call(
344 				pThis, aVtableSlot,
345 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
346 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
347 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
348 				pReturn, pArgs, ppException );
349 		}
350 		break;
351 	}
352 	default:
353 	{
354 		::com::sun::star::uno::RuntimeException aExc(
355 			OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
356 			::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
357 
358 		Type const & rExcType = ::getCppuType( &aExc );
359 		// binary identical null reference
360 		::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
361 	}
362 	}
363 }
364 
365 } } }
366