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