/* * uno2cpp.cxx - Part of the GCC IRIX/MIPS OpenOffice.org Bridge * * By Ralph Thomas * * Under whatever licence you like. * */ /* ISSUES: x Need to get 32bit aligned list x Hey gosh! My head fell off! */ #include #include #include #ifndef _RTL_ALLOC_H_ #include #endif #ifndef _UNO_DATA_H_ #include #endif #ifndef _BRIDGES_CPP_UNO_BRIDGE_HXX_ #include #endif #ifndef _BRIDGES_CPP_UNO_TYPE_MISC_HXX_ #include #endif #include #include #include #include "gcc2_irix_mips.hxx" #define MAX_STRUCT_LENGTH_THING 100 using namespace rtl; using namespace com::sun::star::uno; using namespace std; void UNOVTableInvoke (void* pThis, int methodIndex, long long* gpr, long long* fpr, long long arg, long long* rtn, long long* stack, int stacklength); namespace CPPU_CURRENT_NAMESPACE { long long fixAlignmentForN32 (long long value, typelib_TypeDescription* pTypeDescr) { long long returnValue = 0; switch (pTypeDescr->eTypeClass) { case typelib_TypeClass_DOUBLE: return value; //doubleword length anyway case typelib_TypeClass_FLOAT: return value; //N32 left aligns floating point values. case typelib_TypeClass_HYPER: return value; //doubleword length anyway case typelib_TypeClass_UNSIGNED_HYPER: return value; case typelib_TypeClass_BYTE: case typelib_TypeClass_BOOLEAN: { //One Byte Length ((char*) &returnValue) [7] = ((char*) &value) [0]; return returnValue; } case typelib_TypeClass_CHAR: case typelib_TypeClass_SHORT: case typelib_TypeClass_UNSIGNED_SHORT: { //Two Byte Length ((char*) &returnValue) [6] = ((char*) &value) [0]; ((char*) &returnValue) [7] = ((char*) &value) [1]; return returnValue; } case typelib_TypeClass_LONG: case typelib_TypeClass_UNSIGNED_LONG: case typelib_TypeClass_ENUM: case typelib_TypeClass_STRING: { //Four Byte Length ((char*) &returnValue) [4] = ((char*) &value) [0]; ((char*) &returnValue) [5] = ((char*) &value) [1]; ((char*) &returnValue) [6] = ((char*) &value) [2]; ((char*) &returnValue) [7] = ((char*) &value) [3]; return returnValue; } } return value; } long long fixAlignmentForUNO (long long value, typelib_TypeDescription* pTypeDescr) { long long returnValue = 0; //NB: N32 promotes anything smaller than 32 bits to 32 bits.. Unless typecast... Does GCC? switch (pTypeDescr->eTypeClass) { case typelib_TypeClass_DOUBLE: return value; //doubleword length anyway case typelib_TypeClass_FLOAT: return value; //N32 left aligns floating point values. Does GCC? case typelib_TypeClass_HYPER: return value; //doubleword length anyway case typelib_TypeClass_UNSIGNED_HYPER: return value; case typelib_TypeClass_BYTE: case typelib_TypeClass_BOOLEAN: { //One Byte Length ((char*) &returnValue) [0] = ((char*) &value) [7]; return returnValue; } case typelib_TypeClass_CHAR: case typelib_TypeClass_SHORT: case typelib_TypeClass_UNSIGNED_SHORT: { //Two Byte Length ((char*) &returnValue) [0] = ((char*) &value) [6]; ((char*) &returnValue) [1] = ((char*) &value) [7]; return returnValue; } case typelib_TypeClass_LONG: case typelib_TypeClass_UNSIGNED_LONG: case typelib_TypeClass_ENUM: case typelib_TypeClass_STRING: { //Four Byte Length ((char*) &returnValue) [0] = ((char*) &value) [4]; ((char*) &returnValue) [1] = ((char*) &value) [5]; ((char*) &returnValue) [2] = ((char*) &value) [6]; ((char*) &returnValue) [3] = ((char*) &value) [7]; return returnValue; } } return value; } static void callVirtualMethod (void* pThis, sal_Int32 nVtableIndex, long long* pRegisterReturn, //should be 2. typelib_TypeDescription* pReturnTypeDescr, char* pPT, sal_Int64* pStackLongs, sal_Int32 nStackLongs, uno_Any** pExc, uno_Mapping* pCpp2Uno, bool complexcall) { long long return_space [4]; long long gpr [8]; //64 bit. long long ccall; long long fpr [8]; int reg_i; long long pStack [nStackLongs]; //As long as it will ever need to be. int pStack_i; int c; double dret; //double return. double dret2; long long iret [2]; //return registers. cp_eh_info* pX; void* tmpStorage; uno_Any* tmpPtrAny; reg_i = 0; pStack_i = 0; printf ("callVirtualMethod (%s)\n", pPT); if (complexcall) ccall = 1; else ccall = 0; /* I've used a different string format to the PPC. I need two types: D and I. I make every element of cppArgs 64bits wide (long long). */ while (*pPT != 'X') { c = *pPT; switch (c) { case 'D': //Double - 64bit. if (reg_i < 8) { fpr [reg_i] = *(pStackLongs); reg_i++; } else { pStack [pStack_i] = *pStackLongs; pStack_i++; } pStackLongs++; break; case 'I': //long long - 64bit. if (reg_i < 8) { gpr [reg_i] = (*pStackLongs); reg_i++; } else { pStack [pStack_i] = *((long long*) pStackLongs); pStack_i++; } pStackLongs++; break; } pPT++; } for (int b = 0; b < 8; b++) printf ("FPR %d: 0x%x\n", b, fpr[b]); printf (" Invoking...\n"); try { nVtableIndex ++; UNOVTableInvoke (pThis, nVtableIndex, gpr, fpr, ccall, return_space, pStack, pStack_i); *pExc = 0; } catch (...) { pX = (cp_eh_info*) __cp_eh_info (); gcc291_irix_mips_fillUnoException (pX, *pExc, pCpp2Uno); } //Recast the return value. if (!complexcall) { pRegisterReturn [0] = fixAlignmentForUNO (return_space [0], pReturnTypeDescr); pRegisterReturn [1] = return_space [1]; pRegisterReturn [2] = return_space [2]; pRegisterReturn [3] = return_space [3]; printf ("return_space [2] [part 0] = 0x%x\n", ((int*) &(return_space[2]))[0]); printf ("return_space [2] [part 1] = 0x%x\n", return_space [2]); printf ("return_space [3] = 0x%x\n", return_space [3]); } printf (" ->Returning->\n"); return; } //callVirtualMethod //===================== static void cpp_call ( cppu_unoInterfaceProxy* pThis, sal_Int32 nVtableCall, typelib_TypeDescriptionReference* pReturnTypeRef, sal_Int32 nParams, typelib_MethodParameter* pParams, void* pUnoReturn, void** pUnoArgs, uno_Any** ppUnoExc) { long long pCppArg [nParams + MAX_STRUCT_LENGTH_THING]; //Assume that there will never be a (number of) structure(s) longer than MAX_STRUCT_LENGTH_THING doublewords. char pCppArgString [nParams + MAX_STRUCT_LENGTH_THING]; //Similar assumption int pReconversionIndex [nParams + MAX_STRUCT_LENGTH_THING]; int pParamIndex [nParams + MAX_STRUCT_LENGTH_THING]; int nReconversionIndex = 0; typelib_TypeDescription* ppReconversionTypeDescr [nParams + MAX_STRUCT_LENGTH_THING]; int nCppArg = 0; void* pCppReturn; bool complexcall; bool interfaceRelated; typelib_TypeDescription* pReturnTypeDescr = 0; long long tmpLongLong; long long tmpReturn [4]; TYPELIB_DANGER_GET (&pReturnTypeDescr, pReturnTypeRef); OSL_ENSURE (pReturnTypeDescr, "### expected return type definition!"); printf ("cpp_call\n"); complexcall = false; if (pReturnTypeDescr) { if (cppu_isSimpleType (pReturnTypeDescr) || pReturnTypeDescr->eTypeClass == typelib_TypeClass_HYPER || pReturnTypeDescr->eTypeClass == typelib_TypeClass_UNSIGNED_HYPER) { pCppReturn = pUnoReturn; } else { complexcall = true; } if (pReturnTypeDescr->eTypeClass == typelib_TypeClass_STRUCT || pReturnTypeDescr->eTypeClass == typelib_TypeClass_UNION) { if (pReturnTypeDescr->nSize <= 16) { complexcall = false; pCppReturn = tmpReturn; } } if (complexcall) { //GCC has a very funny idea of what a complex return type is... //On MIPS we say that it's complex if it's bigger than 16 bytes big //GCC doesn't respect this - says that if it's not simple then it's //complex. void* tmpPtr; tmpPtr = alloca (pReturnTypeDescr->nSize); pCppArg [nCppArg] = (long long) tmpPtr; pCppArgString [nCppArg++] = 'I'; pCppReturn = tmpPtr; } interfaceRelated = cppu_relatesToInterface (pReturnTypeDescr); } //put "this" onto the stack. pCppArg [nCppArg] = (long long) pThis->pCppI; pCppArgString [nCppArg++] = 'I'; printf (" Converting %d value(s) from UNO\n", nParams); for (int nPos = 0; nPos < nParams; ++nPos) { printf (" Converting Arg #%d\n", nPos); const typelib_MethodParameter& rParam = pParams [nPos]; typelib_TypeDescription* pParamTypeDescr; pParamTypeDescr = 0; TYPELIB_DANGER_GET (&pParamTypeDescr, rParam.pTypeRef); if (!rParam.bOut && cppu_isSimpleType (pParamTypeDescr)) { uno_copyAndConvertData (&tmpLongLong, pUnoArgs [nPos], pParamTypeDescr, &pThis->pBridge->aUno2Cpp); pCppArg [nCppArg] = fixAlignmentForN32 (tmpLongLong, pParamTypeDescr); tmpLongLong = pCppArg [nCppArg]; ((char*) &tmpLongLong) [4] = ((char*) &pCppArg [nCppArg]) [0]; ((char*) &tmpLongLong) [5] = ((char*) &pCppArg [nCppArg]) [1]; ((char*) &tmpLongLong) [6] = ((char*) &pCppArg [nCppArg]) [2]; ((char*) &tmpLongLong) [7] = ((char*) &pCppArg [nCppArg]) [3]; if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT || pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE) { if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT) pCppArg [nCppArg] = tmpLongLong; pCppArgString [nCppArg++] = 'D'; } else { pCppArgString [nCppArg++] = 'I'; } printf ("SIMPLE PARAM = 0x%x, 0x%x\n",((int*)&tmpLongLong)[0], tmpLongLong); //no longer needed. TYPELIB_DANGER_RELEASE (pParamTypeDescr); } else { /* * GCC does not stick to the N32 ABI with regard to passing structures... * this means that when I port this code to MIPSpro there will be a lot of * work to do here with parsing structues and unions. * */ //Pure Out if (!rParam.bIn) { printf ("PURE OUT\n"); void* tmpPtr; tmpPtr = alloca (pParamTypeDescr->nSize); uno_constructData (tmpPtr, pParamTypeDescr); pReconversionIndex [nReconversionIndex] = nCppArg; ppReconversionTypeDescr [nReconversionIndex] = pParamTypeDescr; //We will release it after reconversion. pParamIndex [nReconversionIndex] = nPos; nReconversionIndex++; pCppArg [nCppArg] = tmpPtr; } //In or In/Out else if (cppu_relatesToInterface (pParamTypeDescr)) { //In/Out printf ("IN/OUT"); void* tmpPtr; tmpPtr = alloca (pParamTypeDescr->nSize); uno_copyAndConvertData (tmpPtr, pUnoArgs [nPos], pParamTypeDescr, &pThis->pBridge->aUno2Cpp); pReconversionIndex [nReconversionIndex] = nCppArg; ppReconversionTypeDescr [nReconversionIndex] = pParamTypeDescr; //We will release it after reconversion. pParamIndex [nReconversionIndex] = nPos; nReconversionIndex++; pCppArg [nCppArg] = tmpPtr; } else { //In printf ("IN\n"); pCppArg [nCppArg] = (long long) pUnoArgs [nPos];//fixAlignmentForN32 (pUnoArgs [nPos], pParamTypeDescr); TYPELIB_DANGER_RELEASE (pParamTypeDescr); } pCppArgString [nCppArg++] = 'I'; } } //Translated all arguments. pCppArgString [nCppArg] = 'X'; callVirtualMethod (pThis->pCppI, nVtableCall, pCppReturn, pReturnTypeDescr, pCppArgString, pCppArg, nCppArg - 1, ppUnoExc, &pThis->pBridge->aCpp2Uno, complexcall); if (*ppUnoExc == 0) { printf ("no exception\n"); for (int i = 0 ; i < nReconversionIndex; i++) { int nIndex = pReconversionIndex [i]; int nPos = pParamIndex [i]; typelib_TypeDescription * pParamTypeDescr = ppReconversionTypeDescr [i]; if (pParams [nPos].bIn) { if (pParams [nPos].bOut) // inout { uno_destructData (pUnoArgs [nPos], pParamTypeDescr, 0); // destroy uno value uno_copyAndConvertData (pUnoArgs [nPos], pCppArg [nIndex], pParamTypeDescr, &pThis->pBridge->aCpp2Uno); } } else // pure out { uno_copyAndConvertData( pUnoArgs [nPos], pCppArg [nIndex], pParamTypeDescr, &pThis->pBridge->aCpp2Uno ); } // destroy temp cpp param => cpp: every param was constructed uno_destructData (pCppArg [nIndex], pParamTypeDescr, cpp_release); TYPELIB_DANGER_RELEASE (pParamTypeDescr); //We've done reconversion - we can release it. } //return value if (interfaceRelated) { void* pReturnValue; if(complexcall) { pReturnValue = pCppReturn; } else { pReturnValue = tmpReturn; } uno_copyAndConvertData (pUnoReturn, pReturnValue, pReturnTypeDescr, &pThis->pBridge->aCpp2Uno); uno_destructData (pReturnValue, pReturnTypeDescr, cpp_release); } else if (complexcall) { memcpy (pUnoReturn, pCppReturn, pReturnTypeDescr->nSize); } TYPELIB_DANGER_RELEASE (pReturnTypeDescr); } else { printf ("exception (oh no)\n"); for (int i = 0; i < nReconversionIndex; i++) { int nIndex = pReconversionIndex [i]; typelib_TypeDescription* pParamTypeDescr = ppReconversionTypeDescr [i]; uno_destructData (pCppArg [nIndex], pParamTypeDescr, cpp_release); TYPELIB_DANGER_RELEASE (pParamTypeDescr); } if (pReturnTypeDescr) TYPELIB_DANGER_RELEASE (pReturnTypeDescr); } printf ("cpp_call returning\n"); } void SAL_CALL cppu_unoInterfaceProxy_dispatch (uno_Interface* pUnoI, const typelib_TypeDescription* pMemberDescr, void* pReturn, void** pArgs, uno_Any** ppException) { cppu_unoInterfaceProxy* pThis; typelib_InterfaceTypeDescription* pTypeDescr; //long long pReturn [8]; pThis = (cppu_unoInterfaceProxy*) pUnoI; pTypeDescr = pThis->pTypeDescr; switch (pMemberDescr->eTypeClass) { case typelib_TypeClass_INTERFACE_ATTRIBUTE: { sal_Int32 nMemberPos; sal_Int32 nVtableCall; nMemberPos = ((typelib_InterfaceMemberTypeDescription*) pMemberDescr)->nPosition; OSL_ENSURE (nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!"); nVtableCall = pTypeDescr->pMapMemberIndexToFunctionIndex [nMemberPos]; OSL_ENSURE (nVtableCall < pTypeDescr->nMapMemberToFunctionIndex, "### illegal vtable index!"); if (pReturn) { //get cpp_call (pThis, nVtableCall, ((typelib_InterfaceAttributeTypeDescription*) pMemberDescr)->pAttributeTypeRef, 0, 0, pReturn, pArgs, ppException); } else { //set long long fakeReturn [4]; typelib_MethodParameter aParam; typelib_TypeDescriptionReference* pReturnTypeRef; OUString aVoidName (RTL_CONSTASCII_USTRINGPARAM ("void")); aParam.pTypeRef = ((typelib_InterfaceAttributeTypeDescription*) pMemberDescr)->pAttributeTypeRef; aParam.bIn = sal_True; aParam.bOut = sal_False; pReturnTypeRef = 0; typelib_typedescriptionreference_new (&pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData); cpp_call (pThis, nVtableCall + 1, pReturnTypeRef, 1, &aParam, fakeReturn, pArgs, ppException); typelib_typedescriptionreference_release (pReturnTypeRef); } break; } case typelib_TypeClass_INTERFACE_METHOD: { sal_Int32 nMemberPos; sal_Int32 nVtableCall; nMemberPos = ((typelib_InterfaceMemberTypeDescription*) pMemberDescr)->nPosition; OSL_ENSURE (nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!"); nVtableCall = pTypeDescr->pMapMemberIndexToFunctionIndex [nMemberPos]; OSL_ENSURE (nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!"); switch (nVtableCall) { //standard calls case 1: //always acquire { (*pUnoI->acquire) (pUnoI); *ppException = 0; break; } case 2: //always release { (*pUnoI->release) (pUnoI); *ppException = 0; break; } case 0: //queryInterface... { typelib_TypeDescription* pTD; pTD = 0; TYPELIB_DANGER_GET (&pTD, reinterpret_cast ((void*) pArgs [0])->getTypeLibType ()); if (pTD) { uno_Interface* pInterface = 0; (*pThis->pBridge->pUnoEnv->getRegisteredInterface) (pThis->pBridge->pUnoEnv, (void**) &pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription*) pTD); if (pInterface) { ::uno_any_construct (reinterpret_cast (pReturn), &pInterface, pTD, 0); (*pInterface->release) (pInterface); TYPELIB_DANGER_RELEASE (pTD); *ppException = 0; break; } TYPELIB_DANGER_RELEASE (pTD); } } default: { cpp_call (pThis, nVtableCall, ((typelib_InterfaceMethodTypeDescription*) pMemberDescr)->pReturnTypeRef, ((typelib_InterfaceMethodTypeDescription*) pMemberDescr)->nParams, ((typelib_InterfaceMethodTypeDescription*) pMemberDescr)->pParams, pReturn, pArgs, ppException); } } break; default: { const RuntimeException aExc ( OUString (RTL_CONSTASCII_USTRINGPARAM ("illegal member type description!")), Reference () ); Type const& rExcType = ::getCppuType (&aExc); ::uno_type_any_construct (*ppException, &aExc, rExcType.getTypeLibType (), 0); } } } } }; //namespace...