/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "abi.hxx" namespace { void call(bridges::cpp_uno::shared::UnoInterfaceProxy* proxy, bridges::cpp_uno::shared::VtableSlot slot, typelib_TypeDescriptionReference* returnType, sal_Int32 count, typelib_MethodParameter* parameters, void* returnValue, void** arguments, uno_Any** exception) { css::uno::TypeDescription rtd(returnType); auto const retConv = bridges::cpp_uno::shared::relatesToInterfaceType(rtd.get()); auto const ret = retConv ? alloca(rtd.get()->nSize) : returnValue; OStringBuffer sig; std::vector args; switch (rtd.get()->eTypeClass) { case typelib_TypeClass_VOID: sig.append('v'); break; case typelib_TypeClass_BOOLEAN: case typelib_TypeClass_BYTE: case typelib_TypeClass_SHORT: case typelib_TypeClass_UNSIGNED_SHORT: case typelib_TypeClass_LONG: case typelib_TypeClass_UNSIGNED_LONG: case typelib_TypeClass_CHAR: case typelib_TypeClass_ENUM: sig.append('i'); break; case typelib_TypeClass_HYPER: case typelib_TypeClass_UNSIGNED_HYPER: sig.append('j'); break; case typelib_TypeClass_FLOAT: sig.append('f'); break; case typelib_TypeClass_DOUBLE: sig.append('d'); break; case typelib_TypeClass_STRING: case typelib_TypeClass_TYPE: case typelib_TypeClass_ANY: case typelib_TypeClass_SEQUENCE: case typelib_TypeClass_INTERFACE: sig.append("vi"); args.push_back(reinterpret_cast(ret)); break; case typelib_TypeClass_STRUCT: { switch (abi_wasm::getKind( reinterpret_cast(rtd.get()))) { case abi_wasm::StructKind::Empty: break; case abi_wasm::StructKind::I32: sig.append('i'); break; case abi_wasm::StructKind::I64: sig.append('j'); break; case abi_wasm::StructKind::F32: sig.append('f'); break; case abi_wasm::StructKind::F64: sig.append('d'); break; case abi_wasm::StructKind::General: sig.append("vi"); args.push_back(reinterpret_cast(ret)); break; } break; } default: O3TL_UNREACHABLE; } sig.append('i'); sal_uInt32 const* const* thisPtr = reinterpret_cast(proxy->getCppI()) + slot.offset; args.push_back(reinterpret_cast(thisPtr)); std::vector cppArgs(count); std::vector ptds(count); for (sal_Int32 i = 0; i != count; ++i) { if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef)) { switch (parameters[i].pTypeRef->eTypeClass) { case typelib_TypeClass_BOOLEAN: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_BYTE: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_SHORT: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_UNSIGNED_SHORT: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_LONG: case typelib_TypeClass_ENUM: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_UNSIGNED_LONG: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_HYPER: sig.append('j'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_UNSIGNED_HYPER: sig.append('j'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_FLOAT: sig.append('f'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_DOUBLE: sig.append('d'); args.push_back(*reinterpret_cast(arguments[i])); break; case typelib_TypeClass_CHAR: sig.append('i'); args.push_back(*reinterpret_cast(arguments[i])); break; default: O3TL_UNREACHABLE; } } else { sig.append('i'); css::uno::TypeDescription ptd(parameters[i].pTypeRef); if (!parameters[i].bIn) { cppArgs[i] = alloca(ptd.get()->nSize); uno_constructData(cppArgs[i], ptd.get()); ptds[i] = ptd; args.push_back(reinterpret_cast(cppArgs[i])); } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd.get())) { cppArgs[i] = alloca(ptd.get()->nSize); uno_copyAndConvertData(cppArgs[i], arguments[i], ptd.get(), proxy->getBridge()->getUno2Cpp()); ptds[i] = ptd; args.push_back(reinterpret_cast(cppArgs[i])); } else { args.push_back(reinterpret_cast(arguments[i])); } } } try { try { callVirtualFunction(sig, (*thisPtr)[slot.index], args.data(), ret); } catch (css::uno::Exception&) { throw; } catch (std::exception& e) { throw css::uno::RuntimeException("C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": " + o3tl::runtimeToOUString(e.what())); } catch (...) { throw css::uno::RuntimeException("C++ code threw unknown exception"); } } catch (css::uno::Exception&) { __cxxabiv1::__cxa_exception* header = reinterpret_cast<__cxxabiv1::__cxa_eh_globals*>(__cxxabiv1::__cxa_get_globals()) ->caughtExceptions; abi_wasm::mapException(header, __cxxabiv1::__cxa_current_exception_type(), *exception, proxy->getBridge()->getCpp2Uno()); for (sal_Int32 i = 0; i != count; ++i) { if (cppArgs[i] != nullptr) { uno_destructData(cppArgs[i], ptds[i].get(), reinterpret_cast(css::uno::cpp_release)); } } return; } *exception = nullptr; for (sal_Int32 i = 0; i != count; ++i) { if (cppArgs[i] != nullptr) { if (parameters[i].bOut) { if (parameters[i].bIn) { uno_destructData(arguments[i], ptds[i].get(), nullptr); } uno_copyAndConvertData(arguments[i], cppArgs[i], ptds[i].get(), proxy->getBridge()->getCpp2Uno()); } uno_destructData(cppArgs[i], ptds[i].get(), reinterpret_cast(css::uno::cpp_release)); } } if (retConv) { uno_copyAndConvertData(returnValue, ret, rtd.get(), proxy->getBridge()->getCpp2Uno()); uno_destructData(ret, rtd.get(), reinterpret_cast(css::uno::cpp_release)); } } } namespace bridges::cpp_uno::shared { void unoInterfaceProxyDispatch(uno_Interface* pUnoI, const typelib_TypeDescription* pMemberDescr, void* pReturn, void* pArgs[], uno_Any** ppException) { bridges::cpp_uno::shared::UnoInterfaceProxy* pThis = static_cast(pUnoI); switch (pMemberDescr->eTypeClass) { case typelib_TypeClass_INTERFACE_ATTRIBUTE: { auto const atd = reinterpret_cast(pMemberDescr); VtableSlot slot(getVtableSlot(atd)); if (pReturn == nullptr) { slot.index += 1; call(pThis, slot, cppu::UnoType::get().getTypeLibType(), 1, &o3tl::temporary( typelib_MethodParameter{ nullptr, atd->pAttributeTypeRef, true, false }), pReturn, pArgs, ppException); } else { call(pThis, slot, atd->pAttributeTypeRef, 0, nullptr, pReturn, pArgs, ppException); } break; } case typelib_TypeClass_INTERFACE_METHOD: { VtableSlot aVtableSlot(getVtableSlot( reinterpret_cast(pMemberDescr))); switch (aVtableSlot.index) { case 1: // acquire uno interface (*pUnoI->acquire)(pUnoI); *ppException = 0; break; case 2: // release uno interface (*pUnoI->release)(pUnoI); *ppException = 0; break; case 0: // queryInterface() opt { typelib_TypeDescription* pTD = 0; TYPELIB_DANGER_GET( &pTD, reinterpret_cast(pArgs[0])->getTypeLibType()); if (pTD) { uno_Interface* pInterface = 0; (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( pThis->getBridge()->getUnoEnv(), (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); } } // else perform queryInterface() [[fallthrough]]; default: { auto const mtd = reinterpret_cast( pMemberDescr); call(pThis, aVtableSlot, mtd->pReturnTypeRef, mtd->nParams, mtd->pParams, pReturn, pArgs, ppException); } } break; } default: { ::com::sun::star::uno::RuntimeException aExc( "illegal member type description!", ::com::sun::star::uno::Reference<::com::sun::star::uno::XInterface>()); css::uno::Type const& rExcType = cppu::UnoType::get(); // binary identical null reference ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), 0); } } } } // namespace bridges::cpp_uno::shared /* vim:set shiftwidth=4 softtabstop=4 expandtab: */