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 #include <malloc.h>
25 #include <rtl/alloc.h>
26 
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include "com/sun/star/uno/RuntimeException.hpp"
29 #include <uno/data.h>
30 
31 #include <bridges/cpp_uno/shared/bridge.hxx>
32 #include <bridges/cpp_uno/shared/types.hxx>
33 #include <bridges/cpp_uno/shared/unointerfaceproxy.hxx>
34 #include <bridges/cpp_uno/shared/vtables.hxx>
35 
36 #include "share.hxx"
37 
38 #include <stdio.h>
39 #include <string.h>
40 
41 using namespace ::rtl;
42 using namespace ::com::sun::star::uno;
43 
44 void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
45     void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn,
46     sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR);
47 
48 #define INSERT_INT32( pSV, nr, pGPR, pDS, bOverFlow )\
49         if (nr < hppa::MAX_WORDS_IN_REGS) \
50         { \
51             pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
52         } \
53         else \
54             bOverFlow = true; \
55         if (bOverFlow) \
56             *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
57 
58 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverFlow )\
59     if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
60     { \
61         ++nr; \
62     } \
63     if ( nr < hppa::MAX_WORDS_IN_REGS ) \
64     { \
65         pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
66         pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
67     } \
68     else \
69         bOverFlow = true; \
70     if ( bOverFlow ) \
71     { \
72         if ( (pDS - pStart) % 2) \
73             ++pDS; \
74         *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
75         *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
76     }
77 
78 #define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverFlow ) \
79     if (nr < hppa::MAX_WORDS_IN_REGS) \
80     { \
81         sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr++]); \
82         pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
83     } \
84     else \
85         bOverFlow = true; \
86     if (bOverFlow) \
87         *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
88 
89 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverFlow ) \
90     if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
91     { \
92         ++nr; \
93     } \
94     if ( nr < hppa::MAX_WORDS_IN_REGS ) \
95     { \
96         sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr+1]); \
97         pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
98         pDouble[1] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
99         nr+=2; \
100     } \
101     else \
102         bOverFlow = true; \
103     if ( bOverFlow ) \
104     { \
105         if ( (pDS - pStart) % 2) \
106             ++pDS; \
107         *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
108         *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
109     }
110 
111 #define INSERT_INT16( pSV, nr, pGPR, pDS, bOverFlow ) \
112     if ( nr < hppa::MAX_WORDS_IN_REGS ) \
113         pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
114     else \
115         bOverFlow = true; \
116     if (bOverFlow) \
117         *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
118 
119 #define INSERT_INT8(  pSV, nr, pGPR, pDS, bOverFlow ) \
120     if ( nr < hppa::MAX_WORDS_IN_REGS ) \
121         pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
122     else \
123         bOverFlow = true; \
124     if (bOverFlow) \
125         *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
126 
127 namespace hppa
128 {
is_complex_struct(const typelib_TypeDescription * type)129     bool is_complex_struct(const typelib_TypeDescription * type)
130     {
131         const typelib_CompoundTypeDescription * p
132             = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
133         for (sal_Int32 i = 0; i < p->nMembers; ++i)
134         {
135             if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
136                 p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
137             {
138                 typelib_TypeDescription * t = 0;
139                 TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
140                 bool b = is_complex_struct(t);
141                 TYPELIB_DANGER_RELEASE(t);
142                 if (b) {
143                     return true;
144                 }
145             }
146             else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
147                 return true;
148         }
149         if (p->pBaseTypeDescription != 0)
150             return is_complex_struct(&p->pBaseTypeDescription->aBase);
151         return false;
152     }
153 
isRegisterReturn(typelib_TypeDescriptionReference * pTypeRef)154     bool isRegisterReturn( typelib_TypeDescriptionReference *pTypeRef )
155     {
156         if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
157             return true;
158         else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
159         {
160             typelib_TypeDescription * pTypeDescr = 0;
161             TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
162 
163             /* If the struct is larger than 8 bytes, then there is a buffer at r8 to stick the return value into  */
164             bool bRet = pTypeDescr->nSize <= 8 && !is_complex_struct(pTypeDescr);
165 
166             TYPELIB_DANGER_RELEASE( pTypeDescr );
167             return bRet;
168         }
169         return false;
170     }
171 }
172 
173 
174 namespace {
175 //=======================================================================
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)176 static void cpp_call(
177     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
178     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
179     typelib_TypeDescriptionReference * pReturnTypeRef,
180     sal_Int32 nParams, typelib_MethodParameter * pParams,
181     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
182 {
183     // max space for: [complex ret ptr], values|ptr ...
184     sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
185         sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
186     sal_uInt32 * pStackStart = pStack;
187 
188     sal_uInt32 pGPR[hppa::MAX_GPR_REGS];
189     double pFPR[hppa::MAX_SSE_REGS];
190     sal_uInt32 nRegs=0;
191 
192     // return
193     typelib_TypeDescription * pReturnTypeDescr = 0;
194     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
195     OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
196 
197     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
198     bool bOverFlow = false;
199     bool bRegisterReturn = true;
200 
201     if (pReturnTypeDescr)
202     {
203 
204         bRegisterReturn = hppa::isRegisterReturn(pReturnTypeRef);
205         if (bRegisterReturn)
206             pCppReturn = pUnoReturn; // direct way for simple types
207         else
208         {
209             // complex return via ptr
210             pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
211                     ? __builtin_alloca( pReturnTypeDescr->nSize )
212                     : pUnoReturn); // direct way
213         }
214     }
215     // push this
216     void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
217         + aVtableSlot.offset;
218     INSERT_INT32( &pAdjustedThisPtr, nRegs, pGPR, pStack, bOverFlow );
219 
220     // stack space
221     OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
222     // args
223     void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
224     // indizes of values this have to be converted (interface conversion cpp<=>uno)
225     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
226     // type descriptions for reconversions
227     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
228 
229     sal_Int32 nTempIndizes   = 0;
230 
231     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
232     {
233         const typelib_MethodParameter & rParam = pParams[nPos];
234         typelib_TypeDescription * pParamTypeDescr = 0;
235         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
236 
237         if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
238         {
239             uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
240                 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
241 
242             switch (pParamTypeDescr->eTypeClass)
243             {
244                 case typelib_TypeClass_HYPER:
245                 case typelib_TypeClass_UNSIGNED_HYPER:
246 #ifdef CMC_DEBUG
247                     fprintf(stderr, "hyper is %llx\n", *((long long*)pCppArgs[nPos]));
248 #endif
249                     INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack, pStackStart, bOverFlow );
250                 break;
251                 case typelib_TypeClass_LONG:
252                 case typelib_TypeClass_UNSIGNED_LONG:
253                 case typelib_TypeClass_ENUM:
254 #ifdef CMC_DEBUG
255                     fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
256 #endif
257                     INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
258                 break;
259                 case typelib_TypeClass_SHORT:
260                 case typelib_TypeClass_CHAR:
261                 case typelib_TypeClass_UNSIGNED_SHORT:
262                     INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
263                 break;
264                 case typelib_TypeClass_BOOLEAN:
265                 case typelib_TypeClass_BYTE:
266                     INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
267                 break;
268                 case typelib_TypeClass_FLOAT:
269                     INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack, bOverFlow );
270                 break;
271                 case typelib_TypeClass_DOUBLE:
272                     INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack, pStackStart, bOverFlow );
273                 break;
274                 default:
275                 break;
276             }
277             // no longer needed
278             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
279         }
280         else // ptr to complex value | ref
281         {
282             if (! rParam.bIn) // is pure out
283             {
284                 // cpp out is constructed mem, uno out is not!
285                 uno_constructData(
286                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
287                     pParamTypeDescr );
288                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
289                 // will be released at reconversion
290                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
291             }
292             // is in/inout
293             else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
294             {
295                 uno_copyAndConvertData(
296                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
297                     pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
298 
299                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
300                 // will be released at reconversion
301                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
302             }
303             else // direct way
304             {
305                 pCppArgs[nPos] = pUnoArgs[nPos];
306                 // no longer needed
307                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
308             }
309             INSERT_INT32( &(pCppArgs[nPos]), nRegs, pGPR, pStack, bOverFlow );
310         }
311     }
312 
313     try
314     {
315         callVirtualMethod(
316             pAdjustedThisPtr, aVtableSlot.index,
317             pCppReturn, pReturnTypeDescr, bRegisterReturn,
318             pStackStart,
319             (pStack - pStackStart), pGPR, pFPR);
320 
321         // NO exception occured...
322         *ppUnoExc = 0;
323 
324         // reconvert temporary params
325         for ( ; nTempIndizes--; )
326         {
327             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
328             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
329 
330             if (pParams[nIndex].bIn)
331             {
332                 if (pParams[nIndex].bOut) // inout
333                 {
334                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
335                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
336                                             pThis->getBridge()->getCpp2Uno() );
337                 }
338             }
339             else // pure out
340             {
341                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
342                                         pThis->getBridge()->getCpp2Uno() );
343             }
344             // destroy temp cpp param => cpp: every param was constructed
345             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
346 
347             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
348         }
349         // return value
350         if (pCppReturn && pUnoReturn != pCppReturn)
351         {
352             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
353                                     pThis->getBridge()->getCpp2Uno() );
354             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
355         }
356     }
357     catch (...)
358     {
359         // fill uno exception
360         fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
361 
362         // temporary params
363         for ( ; nTempIndizes--; )
364         {
365             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
366             // destroy temp cpp param => cpp: every param was constructed
367             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
368             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
369         }
370 
371         // return type
372         if (pReturnTypeDescr)
373             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
374     }
375 }
376 }
377 
378 namespace bridges { namespace cpp_uno { namespace shared {
379 
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)380 void unoInterfaceProxyDispatch(
381     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
382     void * pReturn, void * pArgs[], uno_Any ** ppException )
383 {
384     // is my surrogate
385     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
386           = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
387 #if OSL_DEBUG_LEVEL > 0
388     typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
389 #endif
390 
391     switch (pMemberDescr->eTypeClass)
392     {
393         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
394         {
395 #if OSL_DEBUG_LEVEL > 0
396             // determine vtable call index
397             sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
398             OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
399 #endif
400 
401             VtableSlot aVtableSlot(
402                 getVtableSlot(
403                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
404                    (pMemberDescr)));
405 
406             if (pReturn)
407             {
408                 // dependent dispatch
409                 cpp_call(
410                     pThis, aVtableSlot,
411                     ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
412                     0, 0, // no params
413                     pReturn, pArgs, ppException );
414             }
415             else
416             {
417                 // is SET
418                 typelib_MethodParameter aParam;
419                 aParam.pTypeRef =
420                     ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
421                 aParam.bIn      = sal_True;
422                 aParam.bOut     = sal_False;
423 
424                 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
425                 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
426                 typelib_typedescriptionreference_new(
427                     &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
428 
429                 // dependent dispatch
430                 aVtableSlot.index += 1;
431                 cpp_call(
432                     pThis, aVtableSlot, // get, then set method
433                     pReturnTypeRef,
434                     1, &aParam,
435                     pReturn, pArgs, ppException );
436 
437                 typelib_typedescriptionreference_release( pReturnTypeRef );
438             }
439 
440             break;
441         }
442         case typelib_TypeClass_INTERFACE_METHOD:
443         {
444 #if OSL_DEBUG_LEVEL > 0
445             // determine vtable call index
446             sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
447             OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
448 #endif
449 
450             VtableSlot aVtableSlot(
451                 getVtableSlot(
452                 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
453                   (pMemberDescr)));
454 
455             switch (aVtableSlot.index)
456             {
457                 // standard calls
458                 case 1: // acquire uno interface
459                     (*pUnoI->acquire)( pUnoI );
460                     *ppException = 0;
461                 break;
462                 case 2: // release uno interface
463                     (*pUnoI->release)( pUnoI );
464                     *ppException = 0;
465                     break;
466                 case 0: // queryInterface() opt
467                 {
468                     typelib_TypeDescription * pTD = 0;
469                     TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
470                     if (pTD)
471                     {
472                         uno_Interface * pInterface = 0;
473                         (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
474                             pThis->getBridge()->getUnoEnv(),
475                             (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
476 
477                         if (pInterface)
478                         {
479                             ::uno_any_construct(
480                                 reinterpret_cast< uno_Any * >( pReturn ),
481                                 &pInterface, pTD, 0 );
482                                 (*pInterface->release)( pInterface );
483                                 TYPELIB_DANGER_RELEASE( pTD );
484                                 *ppException = 0;
485                            break;
486                         }
487 
488                         TYPELIB_DANGER_RELEASE( pTD );
489                     }
490                 } // else perform queryInterface()
491                 default:
492                     // dependent dispatch
493                     cpp_call(
494                         pThis, aVtableSlot,
495                         ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
496                         ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
497                         ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
498                         pReturn, pArgs, ppException );
499             }
500             break;
501         }
502         default:
503         {
504             ::com::sun::star::uno::RuntimeException aExc(
505                 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
506                 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
507 
508             Type const & rExcType = ::getCppuType( &aExc );
509             // binary identical null reference
510             ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
511         }
512     }
513 }
514 
515 } } }
516 
517 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
518